From d185316de764c9a1c040b6ab9cc731cd82f3b1da Mon Sep 17 00:00:00 2001 From: mdolhalo Date: Mon, 28 Aug 2023 15:22:49 +0200 Subject: [PATCH] refactoring of "che" test automation framework classes according to CODE_STYLE.md Signed-off-by: mdolhalo --- tests/e2e/.eslintrc.js | 16 +- tests/e2e/CODE_STYLE.md | 144 +++++++++++ tests/e2e/configs/inversify.config.ts | 31 ++- tests/e2e/configs/inversify.types.ts | 20 +- .../e2e/constants/CHROME_DRIVER_CONSTANTS.ts | 14 +- tests/e2e/driver/ChromeDriver.ts | 7 - tests/e2e/index.ts | 2 + tests/e2e/package-lock.json | 22 +- tests/e2e/package.json | 4 +- .../pageobjects/dashboard/CreateWorkspace.ts | 9 +- tests/e2e/pageobjects/dashboard/Dashboard.ts | 7 +- tests/e2e/pageobjects/dashboard/Workspaces.ts | 88 +++---- .../workspace-details/WorkspaceDetails.ts | 49 ++-- .../pageobjects/ide/CheCodeLocatorLoader.ts | 4 +- .../login/interfaces/ICheLoginPage.ts | 2 +- .../login/interfaces/IOcpLoginPage.ts | 2 +- .../login/kubernetes/DexLoginPage.ts | 18 +- .../login/openshift/OcpLoginPage.ts | 48 ++-- .../login/openshift/OcpRedHatLoginPage.ts | 17 +- .../login/openshift/OcpUserLoginPage.ts | 2 +- .../login/openshift/RedHatLoginPage.ts | 33 +-- .../openshift/RegularUserOcpCheLoginPage.ts | 27 +- .../openshift/OcpApplicationPage.ts | 9 +- .../openshift/OcpImportFromGitPage.ts | 38 ++- .../e2e/pageobjects/openshift/OcpMainPage.ts | 49 ++-- tests/e2e/specs/MochaHooks.ts | 8 +- tests/e2e/specs/SmokeTest.spec.ts | 9 +- .../specs/api/ContainerOverridesAPI.spec.ts | 10 +- .../api/DevfileAcceptanceTestAPI.spec.ts | 16 +- tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts | 12 +- tests/e2e/specs/api/PodOverridesAPI.spec.ts | 11 +- .../dashboard-samples/EmptyWorkspace.spec.ts | 10 +- .../specs/dashboard-samples/Quarkus.spec.ts | 13 +- .../RecommendedExtensions.spec.ts | 15 +- .../DevConsoleIntegration.spec.ts | 23 +- tests/e2e/specs/factory/Factory.spec.ts | 20 +- .../specs/factory/NoSetupRepoFactory.spec.ts | 21 +- .../specs/factory/RefusedOAuthFactory.spec.ts | 18 +- .../miscellaneous/PredefinedNamespace.spec.ts | 84 +++---- tests/e2e/tests-library/LoginTests.ts | 6 +- .../tests-library/WorkspaceHandlingTests.ts | 4 +- tests/e2e/utils/BrowserTabsUtil.ts | 16 +- tests/e2e/utils/CheReporter.ts | 46 ++-- .../utils/DevWorkspaceConfigurationHelper.ts | 33 +-- tests/e2e/utils/DevfilesRegistryHelper.ts | 11 +- tests/e2e/utils/DriverHelper.ts | 26 +- tests/e2e/utils/IContextParams.ts | 26 ++ .../IKubernetesCommandLineToolsExecutor.ts | 42 ++++ .../KubernetesCommandLineToolsExecutor.ts | 234 ++++++++++-------- tests/e2e/utils/ShellExecutor.ts | 17 +- tests/e2e/utils/StringUtil.ts | 7 +- 51 files changed, 835 insertions(+), 565 deletions(-) create mode 100644 tests/e2e/CODE_STYLE.md create mode 100644 tests/e2e/utils/IContextParams.ts create mode 100644 tests/e2e/utils/IKubernetesCommandLineToolsExecutor.ts diff --git a/tests/e2e/.eslintrc.js b/tests/e2e/.eslintrc.js index 397a3321723..852e10710a4 100644 --- a/tests/e2e/.eslintrc.js +++ b/tests/e2e/.eslintrc.js @@ -35,7 +35,21 @@ module.exports = { '@typescript-eslint/member-ordering': [ 'error', { - classes: ['field', 'constructor', 'method'] + default: [ + 'static-field', + 'public-field', + 'instance-field', + 'protected-field', + 'private-field', + 'abstract-field', + 'constructor', + 'public-static-method', + 'protected-static-method', + 'private-static-method', + 'public-method', + 'protected-method', + 'private-method' + ] } ], '@typescript-eslint/explicit-function-return-type': [ diff --git a/tests/e2e/CODE_STYLE.md b/tests/e2e/CODE_STYLE.md new file mode 100644 index 00000000000..8fa6d5f74ac --- /dev/null +++ b/tests/e2e/CODE_STYLE.md @@ -0,0 +1,144 @@ +# Coding Standards and Conventions + +### Introducing + +#### Why are coding standards important? + +Coding standards offer several advantages, including: + +1. Increase Code Quality: By adhering to coding standards, developers can create code that is more secure, efficient, + maintainable, and uniform. This, in turn, can result in fewer errors and improved overall performance. + +2. Improved Readability and Maintainability: Coding standards contribute to code that is more comprehensible and easier + to maintain. Consistently formatted code aids other developers in comprehending and modifying it, saving time and + reducing the likelihood of introducing errors. + +3. Accelerated Development: The adherence to coding standards can expedite the development process. When developers + adhere to a predefined set of guidelines, they can produce code more swiftly and with fewer mistakes. Additionally, + uniform code formatting facilitates the identification and resolution of issues. + +4. Better Scalability: Coding standards facilitate the creation of scalable code, simplifying the incorporation of new + features or updates. Consistent coding practices also streamline code maintenance as the codebase expands. + +5. Elevated Collaboration and Communication: Uniform guidelines encourage better understanding and manipulation of code + written by fellow developers. This fosters smoother teamwork and facilitates the sharing of code. + +6. Consistency Across Projects: The adoption of coding standards guarantees a consistent coding approach across various + projects. This simplifies the task of upholding code quality, transitioning between tasks, and fostering + collaborative work. + +### Automated tools + +Automated lint checking and code format performs with ESLint and Prettier tools before every commit using Husky +pre-commit hook. +Full set of rules can be found: + +- [.eslintrc](.eslintrc.js) +- [.prettierrc](.prettierrc.json) + +### Preferable code style + +1. Page-object and util classes + + 1. ✔ Class declaration using dependency injection (inversify library) + + ``` + @injectable() + export class BrowserTabsUtil { + constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + ``` + + 2. Public methods + + - ✔ Declare public methods without "public "keyword + - ✔ Add Logger.debug() inside method to log its name (with optional message) + + ``` + async switchToWindow(windowHandle: string): Promise { + Logger.debug(); // logs BrowserUtils.sswitchToWindow + + await this.driverHelper.getDriver().switchTo().window(windowHandle); + } + ``` + + 3. Locators + + - ✔ For static locators - private static readonly fields type of By + + ``` + private static readonly FACTORY_URL_LOCATOR: By = By.xpath('//input[@id="git-repo-url"]'); + ``` + + - ✔ For dynamic locators - private methods which returns By + + ``` + private getExpandedActionsLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//button[@aria-label='Actions' and @aria-expanded='true']`); + } + ``` + + - ✗ Avoid to declare locators as constant in methods + + ``` + async waitTitleContains(expectedText: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + const pageTitleLocator: By = By.xpath(`//h1[contains(text(), '${expectedText}')]`); + await this.driverHelper.waitVisibility(pageTitleLocator, timeout); + } + ``` + + #### Page object sample: + + ``` + 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"]'); + + constructor( + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + + async waitOpenMainPage(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(OcpMainPage.MAIN_PAGE_HEADER_LOCATOR, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + private getProjectDropdownItemLocator(projectName: string): By { + return By.xpath(`//button//*[text()="${projectName}"]`); + } + } + + ``` + +2. Mocha framework + + - ✔ TDD framework (`suit()`, `test()`) + - ✔ Inject class instances, declare all test data inside test `suit()` function to avoid unnecessary code execution if test suit will not be run + + ``` + suite('name', function(): void { + const webCheCodeLocators: Locators = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + // test specific data + const gitImportReference: string = 'pipeline'; + ``` + + - ✗ Don`t use arrow functions in test declaration https://mochajs.org/#arrow-functions + - ✔ Specs which don`t use browser should have API in name ending (like EmptyWorkspaceAPI.spec) + - ✗ Don\`t create scripts in package.json for each test. Instead of it use [dynamic config](configs/mocharc.ts), `mocha --spec` or `mocha --grep` flags to run specific test. + - ✔ Use test [./constants](constants) to make test flexible + +3. Packages + + 1. Add packages as dev dependencies + 2. If any changes re-create package-lock.json before push + +4. Comments + 1. If some code commented or added as workaround mark it as `//todo` with number of issue to get possibility to find it quickly + ``` + // todo commented due to issue crw-1010 + ``` diff --git a/tests/e2e/configs/inversify.config.ts b/tests/e2e/configs/inversify.config.ts index 00f6fc29ab8..2206ae4a498 100644 --- a/tests/e2e/configs/inversify.config.ts +++ b/tests/e2e/configs/inversify.config.ts @@ -9,10 +9,10 @@ **********************************************************************/ import 'reflect-metadata'; -import { Container } from 'inversify'; +import { Container, decorate, injectable, unmanaged } from 'inversify'; import { IDriver } from '../driver/IDriver'; import { ChromeDriver } from '../driver/ChromeDriver'; -import { CLASSES, TYPES } from './inversify.types'; +import { CLASSES, EXTERNAL_CLASSES, TYPES } from './inversify.types'; import { TestWorkspaceUtil } from '../utils/workspace/TestWorkspaceUtil'; import { IOcpLoginPage } from '../pageobjects/login/interfaces/IOcpLoginPage'; import { OcpUserLoginPage } from '../pageobjects/login/openshift/OcpUserLoginPage'; @@ -44,8 +44,21 @@ import { KubernetesLoginPage } from '../pageobjects/login/kubernetes/KubernetesL import { DexLoginPage } from '../pageobjects/login/kubernetes/DexLoginPage'; import { OAUTH_CONSTANTS } from '../constants/OAUTH_CONSTANTS'; import { BASE_TEST_CONSTANTS, Platform } from '../constants/BASE_TEST_CONSTANTS'; +import { CheCodeLocatorLoader } from '../pageobjects/ide/CheCodeLocatorLoader'; +import { LocatorLoader } from 'monaco-page-objects/out/locators/loader'; +import { OauthPage } from '../pageobjects/git-providers/OauthPage'; +import { DevfilesRegistryHelper } from '../utils/DevfilesRegistryHelper'; +import { Main as Generator } from '@eclipse-che/che-devworkspace-generator/lib/main'; +import { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../utils/KubernetesCommandLineToolsExecutor'; +import { ShellExecutor } from '../utils/ShellExecutor'; -const e2eContainer: Container = new Container({ defaultScope: 'Transient' }); +decorate(injectable(), Generator); +decorate(injectable(), LocatorLoader); +decorate(unmanaged(), LocatorLoader, 0); +decorate(unmanaged(), LocatorLoader, 1); +decorate(unmanaged(), LocatorLoader, 2); + +const e2eContainer: Container = new Container({ defaultScope: 'Transient', skipBaseClassChecks: true }); e2eContainer.bind(TYPES.Driver).to(ChromeDriver).inSingletonScope(); e2eContainer.bind(TYPES.WorkspaceUtil).to(TestWorkspaceUtil); @@ -59,11 +72,12 @@ e2eContainer.bind(CLASSES.WorkspaceDetails).to(WorkspaceDetail e2eContainer.bind(CLASSES.ScreenCatcher).to(ScreenCatcher); e2eContainer.bind(CLASSES.OcpLoginPage).to(OcpLoginPage); e2eContainer.bind(CLASSES.DexLoginPage).to(DexLoginPage); - +e2eContainer.bind(CLASSES.CheCodeLocatorLoader).to(CheCodeLocatorLoader); +e2eContainer.bind(CLASSES.LocatorLoader).to(LocatorLoader); +e2eContainer.bind(CLASSES.OauthPage).to(OauthPage); e2eContainer.bind(CLASSES.OcpMainPage).to(OcpMainPage); e2eContainer.bind(CLASSES.OcpImportFromGitPage).to(OcpImportFromGitPage); e2eContainer.bind(CLASSES.OcpApplicationPage).to(OcpApplicationPage); - e2eContainer.bind(CLASSES.CheApiRequestHandler).to(CheApiRequestHandler); e2eContainer.bind(CLASSES.CreateWorkspace).to(CreateWorkspace); e2eContainer.bind(CLASSES.ProjectAndFileTests).to(ProjectAndFileTests); @@ -72,6 +86,13 @@ e2eContainer.bind(CLASSES.StringUtil).to(StringUtil); e2eContainer.bind(CLASSES.ApiUrlResolver).to(ApiUrlResolver); e2eContainer.bind(CLASSES.WorkspaceHandlingTests).to(WorkspaceHandlingTests); e2eContainer.bind(CLASSES.RedHatLoginPage).to(RedHatLoginPage); +e2eContainer.bind(CLASSES.DevfilesRegistryHelper).to(DevfilesRegistryHelper); +e2eContainer.bind(CLASSES.KubernetesCommandLineToolsExecutor).to(KubernetesCommandLineToolsExecutor); +e2eContainer.bind(CLASSES.ShellExecutor).to(ShellExecutor); +e2eContainer.bind(CLASSES.ContainerTerminal).to(ContainerTerminal); + +e2eContainer.bind(EXTERNAL_CLASSES.Generator).to(Generator); +e2eContainer.bind(EXTERNAL_CLASSES.LocatorLoader).to(LocatorLoader); if (BASE_TEST_CONSTANTS.TS_PLATFORM === Platform.OPENSHIFT) { if (OAUTH_CONSTANTS.TS_SELENIUM_VALUE_OPENSHIFT_OAUTH) { diff --git a/tests/e2e/configs/inversify.types.ts b/tests/e2e/configs/inversify.types.ts index 97b03354d4e..f2d2dff1071 100644 --- a/tests/e2e/configs/inversify.types.ts +++ b/tests/e2e/configs/inversify.types.ts @@ -14,7 +14,9 @@ const TYPES: any = { OcpLogin: Symbol.for('OcpLogin'), WorkspaceUtil: Symbol.for('WorkspaceUtil'), IAuthorizationHeaderHandler: Symbol.for('IAuthorizationHeaderHandler'), - ITokenHandler: Symbol.for('ITokenHandler') + ITokenHandler: Symbol.for('ITokenHandler'), + IKubernetesCommandLineToolsExecutor: Symbol.for('IKubernetesCommandLineToolsExecutor'), + IContextParams: Symbol.for('IContextParams') }; const CLASSES: any = { @@ -38,7 +40,19 @@ const CLASSES: any = { OcpRedHatLoginPage: 'OcpRedHatLoginPage', OcpApplicationPage: 'OcpApplicationPage', OcpMainPage: 'OcpMainPage', - OcpImportFromGitPage: 'OcpImportFromGitPage' + OcpImportFromGitPage: 'OcpImportFromGitPage', + CheCodeLocatorLoader: 'CheCodeLocatorLoader', + LocatorLoader: 'LocatorLoader', + OauthPage: 'OauthPage', + DevfilesRegistryHelper: 'DevfilesRegistryHelper', + KubernetesCommandLineToolsExecutor: 'KubernetesCommandLineToolsExecutor', + ShellExecutor: 'ShellExecutor', + ContainerTerminal: 'ContainerTerminal' }; -export { TYPES, CLASSES }; +const EXTERNAL_CLASSES: any = { + Generator: 'Generator', + LocatorLoader: 'LocatorLoader' +}; + +export { TYPES, CLASSES, EXTERNAL_CLASSES }; diff --git a/tests/e2e/constants/CHROME_DRIVER_CONSTANTS.ts b/tests/e2e/constants/CHROME_DRIVER_CONSTANTS.ts index 99b7d1e522f..e55dceacb3f 100644 --- a/tests/e2e/constants/CHROME_DRIVER_CONSTANTS.ts +++ b/tests/e2e/constants/CHROME_DRIVER_CONSTANTS.ts @@ -8,11 +8,9 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ export const CHROME_DRIVER_CONSTANTS: { - TS_SELENIUM_RESOLUTION_WIDTH: number; TS_SELENIUM_W3C_CHROME_OPTION: boolean; TS_SELENIUM_HEADLESS: boolean; TS_USE_WEB_DRIVER_FOR_TEST: boolean; - TS_SELENIUM_RESOLUTION_HEIGHT: number; TS_SELENIUM_LAUNCH_FULLSCREEN: boolean; TS_SELENIUM_REMOTE_DRIVER_URL: string; } = { @@ -40,15 +38,5 @@ export const CHROME_DRIVER_CONSTANTS: { /** * run browser with an enabled or disabled W3C protocol (on Chrome 76 and upper, it is enabled by default), "true" by default. */ - TS_SELENIUM_W3C_CHROME_OPTION: process.env.TS_SELENIUM_W3C_CHROME_OPTION !== 'false', - - /** - * browser width resolution, "1920" by default. - */ - TS_SELENIUM_RESOLUTION_WIDTH: Number(process.env.TS_SELENIUM_RESOLUTION_WIDTH) || 1920, - - /** - * browser height resolution, "1080" by default. - */ - TS_SELENIUM_RESOLUTION_HEIGHT: Number(process.env.TS_SELENIUM_RESOLUTION_HEIGHT) || 1080 + TS_SELENIUM_W3C_CHROME_OPTION: process.env.TS_SELENIUM_W3C_CHROME_OPTION !== 'false' }; diff --git a/tests/e2e/driver/ChromeDriver.ts b/tests/e2e/driver/ChromeDriver.ts index c1a0706ee80..fbd641bc4e7 100644 --- a/tests/e2e/driver/ChromeDriver.ts +++ b/tests/e2e/driver/ChromeDriver.ts @@ -30,13 +30,6 @@ export class ChromeDriver implements IDriver { return this.driver as ThenableWebDriver; } - async setWindowSize(): Promise { - await (this.driver as ThenableWebDriver) - .manage() - .window() - .setSize(CHROME_DRIVER_CONSTANTS.TS_SELENIUM_RESOLUTION_WIDTH, CHROME_DRIVER_CONSTANTS.TS_SELENIUM_RESOLUTION_HEIGHT); - } - private getDriverOptions(): Options { let options: Options = new Options() .addArguments('--no-sandbox') diff --git a/tests/e2e/index.ts b/tests/e2e/index.ts index 552da32832b..cf50e69b3a3 100644 --- a/tests/e2e/index.ts +++ b/tests/e2e/index.ts @@ -8,6 +8,8 @@ export * from './utils/BrowserTabsUtil'; export * from './utils/DevfilesRegistryHelper'; export * from './utils/DevWorkspaceConfigurationHelper'; export * from './utils/DriverHelper'; +export * from './utils/IContextParams'; +export * from './utils/IKubernetesCommandLineToolsExecutor'; export * from './utils/KubernetesCommandLineToolsExecutor'; export * from './utils/Logger'; export * from './utils/request-handlers/CheApiRequestHandler'; diff --git a/tests/e2e/package-lock.json b/tests/e2e/package-lock.json index 603a15d5190..91a232c2c5c 100644 --- a/tests/e2e/package-lock.json +++ b/tests/e2e/package-lock.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "@eclipse-che/api": "latest", - "inversify": "5.0.1", + "inversify": "6.0.1", "reflect-metadata": "0.1.13" }, "devDependencies": { @@ -42,7 +42,7 @@ "selenium-webdriver": "4.4.0", "shelljs": "^0.8.5", "ts-node": "^10.9.1", - "typescript": "3.9.9", + "typescript": "4.9.4", "vscode-extension-tester-locators": "3.1.0", "yaml": "^2.2.2" } @@ -315,6 +315,12 @@ "follow-redirects": "^1.14.0" } }, + "node_modules/@eclipse-che/che-devworkspace-generator/node_modules/inversify": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.1.1.tgz", + "integrity": "sha512-j8grHGDzv1v+8T1sAQ+3boTCntFPfvxLCkNcxB1J8qA0lUN+fAlSyYd+RXKvaPRL4AGyPxViutBEJHNXOyUdFQ==", + "dev": true + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.40.1", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.40.1.tgz", @@ -3074,9 +3080,9 @@ } }, "node_modules/inversify": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz", - "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz", + "integrity": "sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==" }, "node_modules/ip-regex": { "version": "4.3.0", @@ -5273,9 +5279,9 @@ } }, "node_modules/typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 0ed7907c3ec..fb6317dc149 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -46,13 +46,13 @@ "selenium-webdriver": "4.4.0", "shelljs": "^0.8.5", "ts-node": "^10.9.1", - "typescript": "3.9.9", + "typescript": "4.9.4", "vscode-extension-tester-locators": "3.1.0", "yaml": "^2.2.2" }, "dependencies": { "@eclipse-che/api": "latest", - "inversify": "5.0.1", + "inversify": "6.0.1", "reflect-metadata": "0.1.13" }, "resolutions": { diff --git a/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts b/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts index 45d4aa03e57..a7d0756a7be 100644 --- a/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts +++ b/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts @@ -18,7 +18,7 @@ import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; @injectable() export class CreateWorkspace { - static readonly FACTORY_URL_LOCATOR: By = By.xpath('//input[@id="git-repo-url"]'); + private static readonly FACTORY_URL: By = By.xpath('//input[@id="git-repo-url"]'); constructor( @inject(CLASSES.DriverHelper) @@ -64,11 +64,12 @@ export class CreateWorkspace { async importFromGitUsingUI(factoryUrl: string, timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { Logger.debug(`factoryUrl: "${factoryUrl}"`); - await this.driverHelper.waitVisibility(CreateWorkspace.FACTORY_URL_LOCATOR, timeout); - await this.driverHelper.type(CreateWorkspace.FACTORY_URL_LOCATOR, Key.chord(factoryUrl, Key.ENTER), timeout); + + await this.driverHelper.waitVisibility(CreateWorkspace.FACTORY_URL, timeout); + await this.driverHelper.type(CreateWorkspace.FACTORY_URL, Key.chord(factoryUrl, Key.ENTER), timeout); } - private async clickOnEditorsDropdownListButton(sampleName: string, timeout: number): Promise { + async clickOnEditorsDropdownListButton(sampleName: string, timeout: number): Promise { Logger.debug(`sampleName: "${sampleName}, editor ${BASE_TEST_CONSTANTS.TS_SELENIUM_EDITOR}"`); const editorDropdownListLocator: By = this.getEditorsDropdownListLocator(sampleName); diff --git a/tests/e2e/pageobjects/dashboard/Dashboard.ts b/tests/e2e/pageobjects/dashboard/Dashboard.ts index ea6cba3858c..0eae57ed112 100644 --- a/tests/e2e/pageobjects/dashboard/Dashboard.ts +++ b/tests/e2e/pageobjects/dashboard/Dashboard.ts @@ -40,7 +40,6 @@ export class Dashboard { await this.workspaces.waitPage(); await this.workspaces.waitWorkspaceListItem(workspaceName); await this.workspaces.waitWorkspaceWithRunningStatus(workspaceName); - await this.workspaces.stopWorkspaceByActionsButton(workspaceName); await this.workspaces.waitWorkspaceWithStoppedStatus(workspaceName); } @@ -60,13 +59,13 @@ export class Dashboard { Logger.debug(`"${workspaceName}"`); await this.stopWorkspaceByUI(workspaceName); - await this.workspaces.deleteWorkspaceByActionsButton(workspaceName); - await this.workspaces.waitWorkspaceListItemAbsence(workspaceName); + await this.deleteStoppedWorkspaceByUI(workspaceName); } async openDashboard(): Promise { Logger.debug(); - await this.driverHelper.getDriver().navigate().to(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL); + + await this.driverHelper.navigateToUrl(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL); await this.waitPage(); } diff --git a/tests/e2e/pageobjects/dashboard/Workspaces.ts b/tests/e2e/pageobjects/dashboard/Workspaces.ts index d099d6be940..812137a13d0 100644 --- a/tests/e2e/pageobjects/dashboard/Workspaces.ts +++ b/tests/e2e/pageobjects/dashboard/Workspaces.ts @@ -22,8 +22,13 @@ export enum WorkspaceStatusUI { @injectable() export class Workspaces { - private static readonly ADD_WORKSPACE_BUTTON_XPATH: string = '//button[text()="Add Workspace"]'; - private static readonly WORKSPACE_ITEM_TABLE_NAME_SECTION_XPATH: string = '//td[@data-label="Name"]/span/a'; + private static readonly ADD_WORKSPACE_BUTTON: By = By.xpath('//button[text()="Add Workspace"]'); + private static readonly WORKSPACE_ITEM_TABLE_NAME_SECTION: By = By.xpath('//td[@data-label="Name"]/span/a'); + private static readonly DELETE_WORKSPACE_BUTTON_ENABLED: By = By.xpath( + '//button[@data-testid="delete-workspace-button" and not(@disabled)]' + ); + private static readonly DELETE_CONFIRMATION_CHECKBOX: By = By.xpath('//input[@data-testid="confirmation-checkbox"]'); + private static readonly CONFIRMATION_WINDOW: By = By.xpath('//div[@aria-label="Delete workspaces confirmation window"]'); constructor( @inject(CLASSES.DriverHelper) @@ -33,13 +38,13 @@ export class Workspaces { async waitPage(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { Logger.debug(); - await this.driverHelper.waitVisibility(By.xpath(Workspaces.ADD_WORKSPACE_BUTTON_XPATH), timeout); + await this.driverHelper.waitVisibility(Workspaces.ADD_WORKSPACE_BUTTON, timeout); } async clickAddWorkspaceButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { Logger.debug(); - await this.driverHelper.waitAndClick(By.xpath(Workspaces.ADD_WORKSPACE_BUTTON_XPATH), timeout); + await this.driverHelper.waitAndClick(Workspaces.ADD_WORKSPACE_BUTTON, timeout); } async clickOpenButton(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { @@ -54,9 +59,7 @@ export class Workspaces { ): Promise { Logger.debug(`"${workspaceName}"`); - const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); - - await this.driverHelper.waitVisibility(workspaceListItemLocator, timeout); + await this.driverHelper.waitVisibility(this.getWorkspaceListItemLocator(workspaceName), timeout); } async waitWorkspaceWithRunningStatus( @@ -65,9 +68,7 @@ export class Workspaces { ): Promise { Logger.debug(`"${workspaceName}"`); - const runningStatusLocator: By = this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Running); - - await this.driverHelper.waitVisibility(runningStatusLocator, timeout); + await this.driverHelper.waitVisibility(this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Running), timeout); } async waitWorkspaceWithStoppedStatus( @@ -76,9 +77,7 @@ export class Workspaces { ): Promise { Logger.debug(`"${workspaceName}"`); - const stoppedStatusLocator: By = this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Stopped); - - await this.driverHelper.waitVisibility(stoppedStatusLocator, timeout); + await this.driverHelper.waitVisibility(this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Stopped), timeout); } async clickWorkspaceListItem( @@ -87,9 +86,7 @@ export class Workspaces { ): Promise { Logger.debug(`"${workspaceName}"`); - const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); - - await this.driverHelper.waitAndClick(workspaceListItemLocator, timeout); + await this.driverHelper.waitAndClick(this.getWorkspaceListItemLocator(workspaceName), timeout); } async clickActionsButton(workspaceName: string): Promise { @@ -106,6 +103,7 @@ export class Workspaces { async openActionsPopup(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { Logger.debug(`for the '${workspaceName}' list item`); + await this.clickActionsButton(workspaceName); await this.waitActionsPopup(workspaceName, timeout); } @@ -132,34 +130,28 @@ export class Workspaces { async waitDeleteWorkspaceConfirmationWindow(timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { Logger.debug(); - const confirmationWindowLocator: By = By.xpath('//div[@aria-label="Delete workspaces confirmation window"]'); - - await this.driverHelper.waitVisibility(confirmationWindowLocator, timeout); + await this.driverHelper.waitVisibility(Workspaces.CONFIRMATION_WINDOW, timeout); } async clickToDeleteConfirmationCheckbox(timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug('Workspaces.clickToDeleteConfirmationCheckbox'); - - const deleteConfirmationCheckboxLocator: By = By.xpath('//input[@data-testid="confirmation-checkbox"]'); + Logger.debug(); - await this.driverHelper.waitAndClick(deleteConfirmationCheckboxLocator, timeout); + await this.driverHelper.waitAndClick(Workspaces.DELETE_CONFIRMATION_CHECKBOX, timeout); } async waitAndClickEnabledConfirmationWindowDeleteButton( timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT ): Promise { - Logger.debug('Workspaces.waitEnabledConfirmationWindowDeleteButton'); - - const enabledConfirmationWindowDeleteButton: By = By.xpath('//button[@data-testid="delete-workspace-button" and not(@disabled)]'); + Logger.debug(); - await this.driverHelper.waitAndClick(enabledConfirmationWindowDeleteButton, timeout); + await this.driverHelper.waitAndClick(Workspaces.DELETE_WORKSPACE_BUTTON_ENABLED, timeout); } async deleteWorkspaceByActionsButton( workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT ): Promise { - Logger.debug('Workspaces.deleteWorkspaceByActionsButton'); + Logger.debug(); await this.waitWorkspaceListItem(workspaceName, timeout); await this.openActionsPopup(workspaceName, timeout); @@ -173,7 +165,7 @@ export class Workspaces { workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT ): Promise { - Logger.debug('Workspaces.stopWorkspaceByActionsButton'); + Logger.debug(); await this.waitWorkspaceListItem(workspaceName, timeout); await this.openActionsPopup(workspaceName, timeout); @@ -184,63 +176,63 @@ export class Workspaces { workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT ): Promise { - Logger.debug(`Workspaces.waitWorkspaceListItemAbsence "${workspaceName}"`); + Logger.debug(`"${workspaceName}"`); const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); - - await this.driverHelper.waitDisappearance(workspaceListItemLocator, attempts, polling); + await this.driverHelper.waitDisappearance(this.getWorkspaceListItemLocator(workspaceName), attempts, polling); } async getAllCreatedWorkspacesNames(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug('Workspaces.getAllCreatedWorkspacesNames'); + Logger.debug(); const workspaceNames: string[] = []; try { const workspaceItems: WebElement[] = await this.driverHelper.waitAllPresence( - By.xpath(Workspaces.WORKSPACE_ITEM_TABLE_NAME_SECTION_XPATH), + Workspaces.WORKSPACE_ITEM_TABLE_NAME_SECTION, timeout ); for (const item of workspaceItems) { - Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - try to get ${workspaceItems.indexOf(item)} items name`); + Logger.debug(`try to get ${workspaceItems.indexOf(item)} items name`); workspaceNames.push(await item.getText()); - Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - workspace name is "${workspaceNames[workspaceNames.length - 1]}"`); + Logger.debug(`workspace name is "${workspaceNames[workspaceNames.length - 1]}"`); } } catch (e) { - Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - ${e}`); + Logger.debug(`${e}`); } - Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - ${workspaceNames.length} workspaces have been created in DevSpaces`); + Logger.debug(`${workspaceNames.length} workspaces have been created in DevSpaces`); return workspaceNames; } - private getWorkspaceListItemLocator(workspaceName: string): string { - return `//tr[td/span/a[text()='${workspaceName}']]`; + private getWorkspaceListItemLocator(workspaceName: string): By { + return By.xpath(`//tr[td//a[text()='${workspaceName}']]`); } private getWorkspaceStatusLocator(workspaceName: string, workspaceStatus: WorkspaceStatusUI): By { return By.xpath( - `${this.getWorkspaceListItemLocator( - workspaceName - )}//span[@data-testid='workspace-status-indicator']//*[local-name()='svg' and @fill='${workspaceStatus}']` + `${ + this.getWorkspaceListItemLocator(workspaceName).value + }//span[@data-testid='workspace-status-indicator']//*[local-name()='svg' and @fill='${workspaceStatus}']` ); } private getActionsLocator(workspaceName: string): By { - return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}/td/div/button[@aria-label='Actions']`); + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}/td/div/button[@aria-label='Actions']`); } private getExpandedActionsLocator(workspaceName: string): By { - return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//button[@aria-label='Actions' and @aria-expanded='true']`); + return By.xpath( + `${this.getWorkspaceListItemLocator(workspaceName).value}//button[@aria-label='Actions' and @aria-expanded='true']` + ); } private getActionsPopupButtonLocator(workspaceName: string, buttonText: string): By { - return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//li[@role='menuitem']//button[text()='${buttonText}']`); + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}//li//button[text()='${buttonText}']`); } private getOpenButtonLocator(workspaceName: string): By { - return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//td[@data-key=5]//a[text()='Open']`); + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}//td[@data-key=5]//a[text()='Open']`); } } diff --git a/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts b/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts index d74cc0f7624..3d6ca24b0ec 100644 --- a/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts +++ b/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts @@ -20,11 +20,11 @@ import { ProjectAndFileTests } from '../../../tests-library/ProjectAndFileTests' @injectable() export class WorkspaceDetails { - private static readonly RUN_BUTTON_CSS: string = '#run-workspace-button[che-button-title="Run"]'; - private static readonly OPEN_BUTTON_CSS: string = '#open-in-ide-button[che-button-title="Open"]'; - private static readonly SAVE_BUTTON_CSS: string = 'button[name="save-button"]'; - private static readonly ENABLED_SAVE_BUTTON_CSS: string = 'button[name="save-button"][aria-disabled="false"]'; - private static readonly WORKSPACE_DETAILS_LOADER_CSS: string = 'workspace-details-overview md-progress-linear'; + private static readonly RUN_BUTTON: By = By.css('#run-workspace-button[che-button-title="Run"]'); + private static readonly OPEN_BUTTON: By = By.css('#open-in-ide-button[che-button-title="Open"]'); + private static readonly SAVE_BUTTON: By = By.css('button[name="save-button"]'); + private static readonly ENABLED_SAVE_BUTTON: By = By.css('button[name="save-button"][aria-disabled="false"]'); + private static readonly WORKSPACE_DETAILS_LOADER: By = By.css('workspace-details-overview md-progress-linear'); constructor( @inject(CLASSES.DriverHelper) @@ -41,7 +41,7 @@ export class WorkspaceDetails { ): Promise { Logger.debug(); - await this.driverHelper.waitDisappearance(By.css(WorkspaceDetails.WORKSPACE_DETAILS_LOADER_CSS), attempts, polling); + await this.driverHelper.waitDisappearance(WorkspaceDetails.WORKSPACE_DETAILS_LOADER, attempts, polling); } async saveChanges(): Promise { @@ -65,7 +65,7 @@ export class WorkspaceDetails { async waitWorkspaceTitle(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { Logger.debug(`title: "${workspaceName}"`); - const workspaceTitleLocator: By = By.css(this.getWorkspaceTitleCssLocator(workspaceName)); + const workspaceTitleLocator: By = this.getWorkspaceTitleLocator(workspaceName); await this.driverHelper.waitVisibility(workspaceTitleLocator, timeout); } @@ -73,19 +73,19 @@ export class WorkspaceDetails { async waitRunButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { Logger.debug(); - await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.RUN_BUTTON_CSS), timeout); + await this.driverHelper.waitVisibility(WorkspaceDetails.RUN_BUTTON, timeout); } async clickOnRunButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { Logger.debug(); - await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.RUN_BUTTON_CSS), timeout); + await this.driverHelper.waitAndClick(WorkspaceDetails.RUN_BUTTON, timeout); } async waitOpenButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { Logger.debug(); - await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.OPEN_BUTTON_CSS), timeout); + await this.driverHelper.waitVisibility(WorkspaceDetails.OPEN_BUTTON, timeout); } async openWorkspace( @@ -97,7 +97,6 @@ export class WorkspaceDetails { await this.clickOnOpenButton(timeout); await this.testProjectAndFileCheCode.waitWorkspaceReadinessForCheCodeEditor(); - // await this.testWorkspaceUtil.waitWorkspaceStatus(namespace, workspaceName, WorkspaceStatus.STARTING); } @@ -118,7 +117,7 @@ export class WorkspaceDetails { ]; for (const tabTitle of workspaceDetailsTabs) { - const workspaceDetailsTabLocator: By = By.xpath(this.getTabXpathLocator(tabTitle)); + const workspaceDetailsTabLocator: By = this.getTabLocator(tabTitle); await this.driverHelper.waitVisibility(workspaceDetailsTabLocator, timeout); } @@ -131,46 +130,44 @@ export class WorkspaceDetails { await this.waitTabSelected(tabTitle, timeout); } - private getWorkspaceTitleCssLocator(workspaceName: string): string { - return `che-row-toolbar[che-title='${workspaceName}']`; + private getWorkspaceTitleLocator(workspaceName: string): By { + return By.css(`che-row-toolbar[che-title='${workspaceName}']`); } - private getTabXpathLocator(tabTitle: string): string { - return `//md-tabs-canvas//md-tab-item//span[text()='${tabTitle}']`; + private getTabLocator(tabTitle: string): By { + return By.xpath(`//md-tabs-canvas//md-tab-item//span[text()='${tabTitle}']`); } - private getSelectedTabXpathLocator(tabTitle: string): string { - return `//md-tabs-canvas[@role='tablist']//md-tab-item[@aria-selected='true']//span[text()='${tabTitle}']`; + private getSelectedTabLocator(tabTitle: string): By { + return By.xpath(`//md-tabs-canvas[@role='tablist']//md-tab-item[@aria-selected='true']//span[text()='${tabTitle}']`); } private async waitSaveButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.ENABLED_SAVE_BUTTON_CSS), timeout); + await this.driverHelper.waitVisibility(WorkspaceDetails.ENABLED_SAVE_BUTTON, timeout); } private async waitSaveButtonDisappearance( attempts: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING ): Promise { - await this.driverHelper.waitDisappearance(By.css(WorkspaceDetails.SAVE_BUTTON_CSS), attempts, polling); + await this.driverHelper.waitDisappearance(WorkspaceDetails.SAVE_BUTTON, attempts, polling); } private async clickOnSaveButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.ENABLED_SAVE_BUTTON_CSS), timeout); + await this.driverHelper.waitAndClick(WorkspaceDetails.ENABLED_SAVE_BUTTON, timeout); } private async clickOnOpenButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.OPEN_BUTTON_CSS), timeout); + await this.driverHelper.waitAndClick(WorkspaceDetails.OPEN_BUTTON, timeout); } private async clickOnTab(tabTitle: string, timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - const workspaceDetailsTabLocator: By = By.xpath(this.getTabXpathLocator(tabTitle)); - + const workspaceDetailsTabLocator: By = this.getTabLocator(tabTitle); await this.driverHelper.waitAndClick(workspaceDetailsTabLocator, timeout); } private async waitTabSelected(tabTitle: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - const selectedTabLocator: By = By.xpath(this.getSelectedTabXpathLocator(tabTitle)); - + const selectedTabLocator: By = this.getSelectedTabLocator(tabTitle); await this.driverHelper.waitVisibility(selectedTabLocator, timeout); } } diff --git a/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts b/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts index 0baf6f26264..aa8eb48508c 100644 --- a/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts +++ b/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts @@ -13,6 +13,7 @@ import { LocatorDiff, Locators } from 'monaco-page-objects'; import { By } from 'selenium-webdriver'; import clone from 'clone-deep'; import { MONACO_CONSTANTS } from '../../constants/MONACO_CONSTANTS'; +import { injectable } from 'inversify'; /** * this class allows us to change or add some specific locators base on "monaco-page-object" and "vscode-extension-tester-locators". @@ -20,12 +21,13 @@ import { MONACO_CONSTANTS } from '../../constants/MONACO_CONSTANTS'; * To see full locators list check "node_modules/vscode-extension-tester-locators/out/lib". */ +@injectable() export class CheCodeLocatorLoader extends LocatorLoader { readonly webCheCodeLocators: Locators; constructor() { super( - MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, + MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION, MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, getLocatorsPath() ); diff --git a/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts b/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts index d5d8461319f..5a792c1297b 100644 --- a/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts +++ b/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts @@ -9,5 +9,5 @@ **********************************************************************/ export interface ICheLoginPage { - login(): Promise; + login(user?: string, password?: string): Promise; } diff --git a/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts b/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts index 53deb4d786d..4d09dc10d28 100644 --- a/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts +++ b/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts @@ -9,5 +9,5 @@ **********************************************************************/ export interface IOcpLoginPage { - login(): void; + login(): Promise; } diff --git a/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts b/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts index 26662e12367..b2c189a8e7c 100644 --- a/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts +++ b/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts @@ -17,10 +17,10 @@ import { DriverHelper } from '../../../utils/DriverHelper'; @injectable() export class DexLoginPage { - private static readonly dexPageContentContainer: By = By.className('dex-container'); - private static readonly loginInput: By = By.id('login'); - private static readonly passwordInput: By = By.id('password'); - private static readonly submitButton: By = By.id('submit-login'); + private static readonly DEX_PAGE_CONTENT_CONTAINER: By = By.className('dex-container'); + private static readonly LOGIN_INPUT: By = By.id('login'); + private static readonly PASSWORD_INPUT: By = By.id('password'); + private static readonly SUBMIT_BUTTON: By = By.id('submit-login'); constructor( @inject(CLASSES.DriverHelper) @@ -30,30 +30,30 @@ export class DexLoginPage { async waitDexLoginPage(): Promise { Logger.debug(); - await this.driverHelper.waitVisibility(DexLoginPage.dexPageContentContainer, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper.waitVisibility(DexLoginPage.DEX_PAGE_CONTENT_CONTAINER, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); } async clickOnLoginButton(): Promise { Logger.debug(); - await this.driverHelper.waitAndClick(DexLoginPage.submitButton); + await this.driverHelper.waitAndClick(DexLoginPage.SUBMIT_BUTTON); } async enterUserNameKubernetes(userName: string): Promise { Logger.debug(); - await this.driverHelper.enterValue(DexLoginPage.loginInput, userName); + await this.driverHelper.enterValue(DexLoginPage.LOGIN_INPUT, userName); } async enterPasswordKubernetes(password: string): Promise { Logger.debug(); - await this.driverHelper.enterValue(DexLoginPage.passwordInput, password); + await this.driverHelper.enterValue(DexLoginPage.PASSWORD_INPUT, password); } async waitDexLoginPageDisappearance(): Promise { Logger.debug(); - await this.driverHelper.waitDisappearance(DexLoginPage.dexPageContentContainer, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper.waitDisappearance(DexLoginPage.DEX_PAGE_CONTENT_CONTAINER, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); } } diff --git a/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts b/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts index 2893b0a46e4..f3e7fa5cff2 100644 --- a/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts @@ -18,7 +18,13 @@ import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; @injectable() export class OcpLoginPage { - private static readonly LOGIN_PAGE_OPENSHIFT_XPATH: string = '//*[contains(text(), "Welcome")]'; + private static readonly LOGIN_PAGE_WELCOME_MESSAGE: By = By.xpath('//*[contains(text(), "Welcome")]'); + private static readonly LOGIN_BUTTON: By = By.css('button[type=submit]'); + private static readonly LOGIN_PROVIDER_BUTTON: By = By.xpath(`//a[text()="${OAUTH_CONSTANTS.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}"]`); + private static readonly AUTHORIZE_OPENSHIFT_ACCESS_HEADER: By = By.xpath('//h1[text()="Authorize Access"]'); + private static readonly APPROVE_ACCESS_BUTTON: By = By.css('input[name="approve"]'); + private static readonly USERNAME_INPUT: By = By.id('inputUsername'); + private static readonly PASSWORD_INPUT: By = By.id('inputPassword'); constructor( @inject(CLASSES.DriverHelper) @@ -28,72 +34,54 @@ export class OcpLoginPage { async waitOpenShiftLoginWelcomePage(): Promise { Logger.debug(); - await this.driverHelper.waitVisibility( - By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH), - TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT - ); + await this.driverHelper.waitVisibility(OcpLoginPage.LOGIN_PAGE_WELCOME_MESSAGE, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); } - async clickOnLoginProviderTitle(): Promise { + async waitAndClickOnLoginProviderTitle(): Promise { Logger.debug(); - const loginProviderTitleLocator: By = By.xpath(`//a[text()="${OAUTH_CONSTANTS.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}"]`); - await this.driverHelper.waitAndClick(loginProviderTitleLocator, TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL); + await this.driverHelper.waitAndClick(OcpLoginPage.LOGIN_PROVIDER_BUTTON, TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL); } async isIdentityProviderLinkVisible(): Promise { Logger.debug(); - const loginWithHtpaswdLocator: By = By.xpath(`//a[text()="${OAUTH_CONSTANTS.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}"]`); - return await this.driverHelper.waitVisibilityBoolean(loginWithHtpaswdLocator, 3, 5000); + return await this.driverHelper.waitVisibilityBoolean(OcpLoginPage.LOGIN_PROVIDER_BUTTON, 3, 5000); } async isAuthorizeOpenShiftIdentityProviderPageVisible(): Promise { Logger.debug(); - const authorizeOpenshiftIdentityProviderPageLocator: By = By.xpath('//h1[text()="Authorize Access"]'); - return await this.driverHelper.isVisible(authorizeOpenshiftIdentityProviderPageLocator); - } - - async waitAuthorizeOpenShiftIdentityProviderPage(): Promise { - Logger.debug(); - - const authorizeOpenshiftIdentityProviderPageLocator: By = By.xpath('//h1[text()="Authorize Access"]'); - await this.driverHelper.waitVisibility( - authorizeOpenshiftIdentityProviderPageLocator, - TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT - ); + return await this.driverHelper.isVisible(OcpLoginPage.AUTHORIZE_OPENSHIFT_ACCESS_HEADER); } async clickOnApproveAuthorizeAccessButton(): Promise { Logger.debug(); - const approveAuthorizeAccessOcpLocator: By = By.css('input[name="approve"]'); - await this.driverHelper.waitAndClick(approveAuthorizeAccessOcpLocator); + await this.driverHelper.waitAndClick(OcpLoginPage.APPROVE_ACCESS_BUTTON); } async enterUserNameOpenShift(userName: string): Promise { Logger.debug(`"${userName}"`); - await this.driverHelper.enterValue(By.id('inputUsername'), userName); + await this.driverHelper.enterValue(OcpLoginPage.USERNAME_INPUT, userName); } - async enterPasswordOpenShift(passw: string): Promise { + async enterPasswordOpenShift(userPassword: string): Promise { Logger.debug(); - await this.driverHelper.enterValue(By.id('inputPassword'), passw); + await this.driverHelper.enterValue(OcpLoginPage.PASSWORD_INPUT, userPassword); } async clickOnLoginButton(): Promise { Logger.debug(); - const loginButtonLocator: By = By.css('button[type=submit]'); - await this.driverHelper.waitAndClick(loginButtonLocator); + await this.driverHelper.waitAndClick(OcpLoginPage.LOGIN_BUTTON); } async waitDisappearanceOpenShiftLoginWelcomePage(): Promise { Logger.debug(); - await this.driverHelper.waitDisappearance(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH)); + await this.driverHelper.waitDisappearance(OcpLoginPage.LOGIN_PAGE_WELCOME_MESSAGE); } } diff --git a/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts b/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts index 9ff8eb36dfb..d904cb4774d 100644 --- a/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts @@ -20,8 +20,9 @@ import { Logger } from '../../../utils/Logger'; @injectable() export class OcpRedHatLoginPage implements ICheLoginPage { - private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR: string = '//div[@class="panel-login"]'; - private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR: string = `${this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR}/div[contains(@class, 'panel-content')]/form/button`; + private static readonly OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON: By = By.xpath( + '//div[@class="panel-login"]/div[contains(@class, "panel-content")]/form/button' + ); constructor( @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage, @@ -33,17 +34,11 @@ export class OcpRedHatLoginPage implements ICheLoginPage { async login(): Promise { Logger.debug(); - - Logger.debug('wait for LogInWithOpenShift page and click button'); - await this.driverHelper.waitPresence( - By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), + await this.driverHelper.waitAndClick( + OcpRedHatLoginPage.OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT ); - await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); - - await this.ocpLogin.isIdentityProviderLinkVisible(); - await this.ocpLogin.clickOnLoginProviderTitle(); - + await this.ocpLogin.waitAndClickOnLoginProviderTitle(); await this.redHatLogin.waitRedHatLoginWelcomePage(); await this.redHatLogin.enterUserNameRedHat(); await this.redHatLogin.clickNextButton(); diff --git a/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts b/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts index cbc3645cdfe..c78fb51721a 100644 --- a/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts @@ -23,7 +23,7 @@ export class OcpUserLoginPage implements IOcpLoginPage { Logger.debug(); if (OAUTH_CONSTANTS.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE !== '') { - await this.ocpLogin.clickOnLoginProviderTitle(); + await this.ocpLogin.waitAndClickOnLoginProviderTitle(); } await this.ocpLogin.waitOpenShiftLoginWelcomePage(); diff --git a/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts b/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts index 2c3298d7f89..5d51998ab8e 100644 --- a/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts @@ -14,13 +14,14 @@ import { CLASSES } from '../../../configs/inversify.types'; import { DriverHelper } from '../../../utils/DriverHelper'; import { Logger } from '../../../utils/Logger'; import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; @injectable() export class RedHatLoginPage { - private readonly USERNAME_INPUT_ID: string = 'username-verification'; - private readonly PASSWORD_INPUT_ID: string = 'password'; - private readonly NEXT_BUTTON_ID: string = 'login-show-step2'; - private readonly LOGIN_BUTTON_ID: string = 'rh-password-verification-submit-button'; + private static readonly USERNAME_INPUT: By = By.id('username-verification'); + private static readonly PASSWORD_INPUT: By = By.id('password'); + private static readonly NEXT_BUTTON: By = By.id('login-show-step2'); + private static readonly LOGIN_BUTTON: By = By.id('rh-password-verification-submit-button'); constructor( @inject(CLASSES.DriverHelper) @@ -29,37 +30,37 @@ export class RedHatLoginPage { async waitRedHatLoginWelcomePage(): Promise { Logger.debug(); - await this.driverHelper.waitVisibility(By.id(this.USERNAME_INPUT_ID)); + + await this.driverHelper.waitVisibility(RedHatLoginPage.USERNAME_INPUT, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); } async enterPasswordRedHat(): Promise { Logger.debug(); - const passwordFieldLocator: By = By.id(this.PASSWORD_INPUT_ID); - await this.driverHelper.waitVisibility(passwordFieldLocator, 3000); - await this.driverHelper.enterValue(passwordFieldLocator, OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); + + await this.driverHelper.enterValue(RedHatLoginPage.PASSWORD_INPUT, OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); } async clickOnLoginButton(): Promise { Logger.debug(); - const loginButtonLocator: By = By.id(this.LOGIN_BUTTON_ID); - await this.driverHelper.waitAndClick(loginButtonLocator); + + await this.driverHelper.waitAndClick(RedHatLoginPage.LOGIN_BUTTON); } async waitDisappearanceRedHatLoginWelcomePage(): Promise { Logger.debug(); - await this.driverHelper.waitDisappearance(By.id(this.LOGIN_BUTTON_ID)); + + await this.driverHelper.waitDisappearance(RedHatLoginPage.LOGIN_BUTTON); } async enterUserNameRedHat(): Promise { Logger.debug(); - const usernameFieldLocator: By = By.id(this.USERNAME_INPUT_ID); - await this.driverHelper.waitVisibility(usernameFieldLocator, 20000); - await this.driverHelper.enterValue(usernameFieldLocator, OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); + + await this.driverHelper.enterValue(RedHatLoginPage.USERNAME_INPUT, OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); } async clickNextButton(): Promise { Logger.debug(); - const nextButtonLocator: By = By.id(this.NEXT_BUTTON_ID); - await this.driverHelper.waitAndClick(nextButtonLocator); + + await this.driverHelper.waitAndClick(RedHatLoginPage.NEXT_BUTTON); } } diff --git a/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts b/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts index 478ee6ac448..6761a194d7a 100644 --- a/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts @@ -20,8 +20,9 @@ import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; @injectable() export class RegularUserOcpCheLoginPage implements ICheLoginPage { - private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR: string = '//div[@class="panel-login"]'; - private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR: string = `${this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR}/div[contains(@class, 'panel-content')]/form/button`; + private static readonly OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON: By = By.xpath( + '//div[@class="panel-login"]/div[contains(@class, "panel-content")]/form/button' + ); constructor( @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage, @@ -29,28 +30,32 @@ export class RegularUserOcpCheLoginPage implements ICheLoginPage { private readonly driverHelper: DriverHelper ) {} - async login(): Promise { + /** + * @param userName + * @param password + */ + async login( + userName: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME, + password: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD + ): Promise { Logger.debug(); - Logger.debug('wait for LogInWithOpenShift page and click button'); - await this.driverHelper.waitPresence( - By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), + await this.driverHelper.waitAndClick( + RegularUserOcpCheLoginPage.OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT ); - await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); if (await this.ocpLogin.isIdentityProviderLinkVisible()) { - await this.ocpLogin.clickOnLoginProviderTitle(); + await this.ocpLogin.waitAndClickOnLoginProviderTitle(); } await this.ocpLogin.waitOpenShiftLoginWelcomePage(); - await this.ocpLogin.enterUserNameOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); - await this.ocpLogin.enterPasswordOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); + await this.ocpLogin.enterUserNameOpenShift(userName); + await this.ocpLogin.enterPasswordOpenShift(password); await this.ocpLogin.clickOnLoginButton(); await this.ocpLogin.waitDisappearanceOpenShiftLoginWelcomePage(); if (await this.ocpLogin.isAuthorizeOpenShiftIdentityProviderPageVisible()) { - await this.ocpLogin.waitAuthorizeOpenShiftIdentityProviderPage(); await this.ocpLogin.clickOnApproveAuthorizeAccessButton(); } } diff --git a/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts b/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts index 26a3a8c7f92..018c95bf240 100644 --- a/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts +++ b/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts @@ -18,8 +18,8 @@ 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"]'); + private static readonly APPLICATION_ICON: By = By.xpath('//*[@data-test-id="base-node-handler"]'); + private static readonly EDIT_SOURCE_CODE_ICON: By = By.xpath('//*[@aria-label="Edit source code"]'); constructor( @inject(CLASSES.DriverHelper) @@ -31,13 +31,14 @@ export class OcpApplicationPage { async waitApplicationIcon(): Promise { Logger.debug(); - await this.driverHelper.waitPresence(OcpApplicationPage.APPLICATION_ICON_LOCATOR, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper.waitPresence(OcpApplicationPage.APPLICATION_ICON, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); } async waitAndOpenEditSourceCodeIcon(): Promise { Logger.debug(); + const parentGUID: string = await this.browserTabsUtil.getCurrentWindowHandle(); - await this.driverHelper.waitAndClick(OcpApplicationPage.EDIT_SOURCE_CODE_ICON_LOCATOR); + await this.driverHelper.waitAndClick(OcpApplicationPage.EDIT_SOURCE_CODE_ICON); await this.browserTabsUtil.waitAndSwitchToAnotherWindow(parentGUID, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); } } diff --git a/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts b/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts index 8645390c371..f658bba984b 100644 --- a/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts +++ b/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts @@ -18,17 +18,15 @@ 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"]'); + private static readonly GIT_URL_INPUT: By = By.id('form-input-git-url-field'); + private static readonly SHOW_ADVANCED_GIT_OPTIONS_LINK: By = By.xpath('//*[text()="Show advanced Git options"]//ancestor::button'); + private static readonly HIDE_ADVANCED_GIT_OPTIONS: By = By.xpath('//*[text()="Hide advanced Git options"]'); + private static readonly GIT_REFERENCE_INPUT: By = By.id('form-input-git-ref-field'); + private static readonly EDIT_IMPORT_STRATEGY_LINK: By = By.xpath('//*[text()="Edit Import Strategy"]//ancestor::button'); + private static readonly BUILDER_IMAGE_STRATEGY_ITEM: By = By.xpath('//*[text()="Builder Image"]//parent::div//parent::div'); + private static readonly ADD_LABEL_LINK: By = By.xpath('//button[text()="Labels"]'); + private static readonly ADD_LABEL_INPUT: By = By.id('form-selector-labels-field'); + private static readonly SUBMIT_BUTTON: By = By.xpath('//*[@data-test-id="submit-button"]'); constructor( @inject(CLASSES.DriverHelper) @@ -38,41 +36,41 @@ export class OcpImportFromGitPage { async enterGitRepoUrl(gitRepoUrl: string): Promise { Logger.debug(); - await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_URL_INPUT_LOCATOR, gitRepoUrl); + await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_URL_INPUT, gitRepoUrl); } async clickOnAdvancedOptionsButton(): Promise { Logger.debug(); - if (!(await this.driverHelper.isVisible(OcpImportFromGitPage.HIDE_ADVANCED_GIT_OPTIONS_LOCATOR))) { - await this.driverHelper.waitAndClick(OcpImportFromGitPage.SHOW_ADVANCED_GIT_OPTIONS_LINK_LOCATOR); + if (!(await this.driverHelper.isVisible(OcpImportFromGitPage.HIDE_ADVANCED_GIT_OPTIONS))) { + await this.driverHelper.waitAndClick(OcpImportFromGitPage.SHOW_ADVANCED_GIT_OPTIONS_LINK); } } async enterGitReference(gitReference: string): Promise { Logger.debug(`"${gitReference}"`); - await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_REFERENCE_INPUT_LOCATOR, gitReference); + await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_REFERENCE_INPUT, gitReference); } async selectBuilderImageImportStrategy(): Promise { Logger.debug(); - await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.EDIT_IMPORT_STRATEGY_LINK_LOCATOR); - await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.BUILDER_IMAGE_STRATEGY_ITEM_LOCATOR); + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.EDIT_IMPORT_STRATEGY_LINK); + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.BUILDER_IMAGE_STRATEGY_ITEM); } async addLabel(label: string): Promise { Logger.debug(`"${label}"`); - await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.ADD_LABEL_LINK_LOCATOR); - await this.driverHelper.scrollToAndEnterValue(OcpImportFromGitPage.ADD_LABEL_INPUT_LOCATOR, label); + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.ADD_LABEL_LINK); + await this.driverHelper.scrollToAndEnterValue(OcpImportFromGitPage.ADD_LABEL_INPUT, label); } async submitConfiguration(): Promise { Logger.debug(); - await this.driverHelper.waitAndClick(OcpImportFromGitPage.SUBMIT_BUTTON_LOCATOR); + await this.driverHelper.waitAndClick(OcpImportFromGitPage.SUBMIT_BUTTON); return e2eContainer.get(CLASSES.OcpApplicationPage); } diff --git a/tests/e2e/pageobjects/openshift/OcpMainPage.ts b/tests/e2e/pageobjects/openshift/OcpMainPage.ts index 9378a2c6930..e9792728198 100644 --- a/tests/e2e/pageobjects/openshift/OcpMainPage.ts +++ b/tests/e2e/pageobjects/openshift/OcpMainPage.ts @@ -19,43 +19,35 @@ 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 readonly SKIP_TOUR_BUTTON_LOCATOR: By = By.xpath('//*[text()="Skip tour"]'); + private static readonly MAIN_PAGE_HEADER: By = By.id('page-main-header'); + private static readonly SELECT_ROLE_BUTTON: By = By.xpath('//*[@data-test-id="perspective-switcher-toggle"]'); + private static readonly ADD_BUTTON: By = By.xpath('//*[@data-test-id="+Add-header"]'); + private static readonly IMPORT_FROM_GIT_ITEM: By = By.xpath('//*[@data-test="item import-from-git"]'); + private static readonly SELECT_PROJECT_DROPDOWN: By = By.xpath('//div[@class="co-namespace-dropdown"]//button'); + private static readonly PROJECT_FILTER_INPUT: By = By.xpath('//*[@data-test="dropdown-text-filter"]'); + private static readonly SKIP_TOUR_BUTTON: By = By.xpath('//*[text()="Skip tour"]'); constructor( @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper ) {} - private static getRoleLocator(role: string): By { - return By.xpath(`//a//*[text()="${role}"]`); - } - - private static getProjectDropdownItemLocator(projectName: string): By { - return By.xpath(`//button//*[text()="${projectName}"]`); - } - async waitOpenMainPage(): Promise { Logger.debug(); - await this.driverHelper.waitVisibility(OcpMainPage.MAIN_PAGE_HEADER_LOCATOR, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper.waitVisibility(OcpMainPage.MAIN_PAGE_HEADER, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); } async clickOnSelectRoleButton(): Promise { Logger.debug(); - await this.driverHelper.waitAndClick(OcpMainPage.SELECT_ROLE_BUTTON_LOCATOR); + await this.driverHelper.waitAndClick(OcpMainPage.SELECT_ROLE_BUTTON); } async clickAddToProjectButton(): Promise { Logger.debug(); - await this.driverHelper.waitAndClick(OcpMainPage.ADD_BUTTON_LOCATOR); + await this.driverHelper.waitAndClick(OcpMainPage.ADD_BUTTON); } async selectDeveloperRole(): Promise { @@ -71,7 +63,7 @@ export class OcpMainPage { async selectImportFromGitMethod(): Promise { Logger.debug(); - await this.driverHelper.waitAndClick(OcpMainPage.IMPORT_FROM_GIT_ITEM_LOCATOR); + await this.driverHelper.waitAndClick(OcpMainPage.IMPORT_FROM_GIT_ITEM); return e2eContainer.get(CLASSES.OcpImportFromGitPage); } @@ -85,22 +77,29 @@ export class OcpMainPage { async selectProject(projectName: string): Promise { Logger.debug(); - 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)); + await this.driverHelper.waitAndClick(OcpMainPage.SELECT_PROJECT_DROPDOWN); + await this.driverHelper.enterValue(OcpMainPage.PROJECT_FILTER_INPUT, 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}"]`); } private async selectRole(role: string): Promise { Logger.debug(`selecting role ${role}`); - await this.driverHelper.waitAndClick(OcpMainPage.getRoleLocator(role)); + await this.driverHelper.waitAndClick(this.getRoleLocator(role)); } private async tryToSkipWebTour(): Promise { Logger.debug(); - if (await this.driverHelper.isVisible(OcpMainPage.SKIP_TOUR_BUTTON_LOCATOR)) { - await this.driverHelper.waitAndClick(OcpMainPage.SKIP_TOUR_BUTTON_LOCATOR); + if (await this.driverHelper.isVisible(OcpMainPage.SKIP_TOUR_BUTTON)) { + await this.driverHelper.waitAndClick(OcpMainPage.SKIP_TOUR_BUTTON); Logger.debug('welcome tour modal dialog was located and skipped'); } else { diff --git a/tests/e2e/specs/MochaHooks.ts b/tests/e2e/specs/MochaHooks.ts index 898ecd6d07a..d13240024f2 100644 --- a/tests/e2e/specs/MochaHooks.ts +++ b/tests/e2e/specs/MochaHooks.ts @@ -23,8 +23,6 @@ import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; import { MONACO_CONSTANTS } from '../constants/MONACO_CONSTANTS'; const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); - let latestWorkspace: string = ''; export function registerRunningWorkspace(workspaceName: string): void { @@ -44,8 +42,8 @@ exports.mochaHooks = { CheApiRequestHandler.enableResponseInterceptor(); } }, + // init vscode-extension-tester monaco-page-objects function initMonacoPageObjects(): void { - // init vscode-extension-tester monaco-page-objects monacoPageObjects.initPageObjects( MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION, MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, @@ -66,11 +64,11 @@ exports.mochaHooks = { ], afterEach: [ // stop and remove running workspace - function (this: Mocha.Context): void { + function deleteWorkspaceOnFailedTest(this: Mocha.Context): void { if (this.currentTest?.state === 'failed') { if (BASE_TEST_CONSTANTS.DELETE_WORKSPACE_ON_FAILED_TEST) { Logger.info('Property DELETE_WORKSPACE_ON_FAILED_TEST is true - trying to stop and delete running workspace with API.'); - // await + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); testWorkspaceUtil.stopAndDeleteWorkspaceByName(latestWorkspace); } } diff --git a/tests/e2e/specs/SmokeTest.spec.ts b/tests/e2e/specs/SmokeTest.spec.ts index 34492294a23..cd23208adf9 100644 --- a/tests/e2e/specs/SmokeTest.spec.ts +++ b/tests/e2e/specs/SmokeTest.spec.ts @@ -21,12 +21,11 @@ import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; import { expect } from 'chai'; import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); - suite('The SmokeTest userstory', function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); const factoryUrl: string = FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git'; let projectSection: ViewSection; diff --git a/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts b/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts index 07de2b69b6b..d3faf1fc3d1 100644 --- a/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts +++ b/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts @@ -13,11 +13,17 @@ import path from 'path'; import YAML from 'yaml'; import { expect } from 'chai'; import { ShellExecutor } from '../../utils/ShellExecutor'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; suite('Test defining container overrides via attribute.', function (): void { const pathToSampleFile: string = path.resolve('resources/container-overrides.yaml'); const workspaceName: string = YAML.parse(fs.readFileSync(pathToSampleFile, 'utf8')).metadata.name; - const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(workspaceName); + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + kubernetesCommandLineToolsExecutor.workspaceName = workspaceName; + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); suiteSetup('Login into OC client', function (): void { kubernetesCommandLineToolsExecutor.loginToOcp(); @@ -29,7 +35,7 @@ suite('Test defining container overrides via attribute.', function (): void { test('Apply container-overrides sample as DevWorkspace with OC client', function (): void { kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsFile(pathToSampleFile); - ShellExecutor.wait(5); + shellExecutor.wait(5); }); test('Check that fields are overridden in the Deployment for DevWorkspace', function (): void { diff --git a/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts b/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts index 940d9c395da..8066e0e3fe7 100644 --- a/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts +++ b/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts @@ -7,14 +7,15 @@ * * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigurationHelper'; import { ShellString } from 'shelljs'; import { expect } from 'chai'; import { DevfileContext } from '@eclipse-che/che-devworkspace-generator/lib/api/devfile-context'; import { StringUtil } from '../../utils/StringUtil'; -// import { DevfilesRegistryHelper } from '../../utils/DevfilesRegistryHelper'; import { Logger } from '../../utils/Logger'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; /** * dynamically generating tests @@ -23,7 +24,8 @@ import { Logger } from '../../utils/Logger'; // todo: skipped while don`t use to avoid sending useless requests // eslint-disable-next-line @typescript-eslint/require-await void (async function (): Promise { - // const devfilesRegistryHelper: DevfilesRegistryHelper = new DevfilesRegistryHelper(); + // const devfilesRegistryHelper: DevfilesRegistryHelper = e2eContainer.get(CLASSES.DevfilesRegistryHelper); + const devfileSamples: any = []; // devfileSamples = await devfilesRegistryHelper.collectPathsToDevfilesFromRegistry(); @@ -33,7 +35,7 @@ void (async function (): Promise { this.timeout(1500000); // 25 minutes because build of Quarkus sample takes 20+ minutes let devWorkspaceConfigurationHelper: DevWorkspaceConfigurationHelper; let kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor; - let containerTerminal: KubernetesCommandLineToolsExecutor.ContainerTerminal; + let containerTerminal: ContainerTerminal; let devfileContext: DevfileContext; let devWorkspaceName: string | undefined; let clonedProjectName: string; @@ -46,9 +48,9 @@ void (async function (): Promise { }); devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext(); devWorkspaceName = devfileContext?.devWorkspace?.metadata?.name; - - kubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(devWorkspaceName); - containerTerminal = new KubernetesCommandLineToolsExecutor.ContainerTerminal(kubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor = e2eContainer.get(CLASSES.KubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor.workspaceName = devWorkspaceName; + containerTerminal = e2eContainer.get(CLASSES.ContainerTerminal); kubernetesCommandLineToolsExecutor.loginToOcp(); }); diff --git a/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts b/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts index c390dcb9590..1ccff56e2c0 100644 --- a/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts +++ b/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; import { expect } from 'chai'; import { ShellString } from 'shelljs'; import { StringUtil } from '../../utils/StringUtil'; @@ -15,6 +15,8 @@ import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigu import { DevfileContext } from '@eclipse-che/che-devworkspace-generator/lib/api/devfile-context'; import { API_TEST_CONSTANTS } from '../../constants/API_TEST_CONSTANTS'; import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; suite('Empty workspace API test', function (): void { // works only for root user @@ -25,7 +27,7 @@ suite('Empty workspace API test', function (): void { let kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor; let devfileContext: DevfileContext; let devWorkspaceName: string | undefined; - let containerTerminal: KubernetesCommandLineToolsExecutor.ContainerTerminal; + let containerTerminal: ContainerTerminal; const gitRepository: string = 'https://github.com/crw-qe/web-nodejs-sample'; @@ -38,8 +40,10 @@ suite('Empty workspace API test', function (): void { }); devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext(); devWorkspaceName = devfileContext?.devWorkspace?.metadata?.name; - kubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(devWorkspaceName, namespace); - containerTerminal = new KubernetesCommandLineToolsExecutor.ContainerTerminal(kubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor = e2eContainer.get(CLASSES.KubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor.workspaceName = devWorkspaceName; + kubernetesCommandLineToolsExecutor.namespace = namespace; + containerTerminal = e2eContainer.get(CLASSES.ContainerTerminal); }); test('Create empty workspace', function (): void { diff --git a/tests/e2e/specs/api/PodOverridesAPI.spec.ts b/tests/e2e/specs/api/PodOverridesAPI.spec.ts index b898526da9a..f02cf76af9b 100644 --- a/tests/e2e/specs/api/PodOverridesAPI.spec.ts +++ b/tests/e2e/specs/api/PodOverridesAPI.spec.ts @@ -14,14 +14,19 @@ import YAML from 'yaml'; import { expect } from 'chai'; import { ShellExecutor } from '../../utils/ShellExecutor'; import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; suite('Test defining pod overrides via attribute.', function (): void { const pathToSampleFile: string = path.resolve( `resources/pod-overrides${BASE_TEST_CONSTANTS.IS_CLUSTER_DISCONNECTED() ? '-airgap' : ''}.yaml` ); const workspaceName: string = YAML.parse(fs.readFileSync(pathToSampleFile, 'utf8')).metadata.name; - const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(workspaceName); - + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + kubernetesCommandLineToolsExecutor.workspaceName = workspaceName; + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); suiteSetup('Login into OC client', function (): void { kubernetesCommandLineToolsExecutor.loginToOcp(); }); @@ -32,7 +37,7 @@ suite('Test defining pod overrides via attribute.', function (): void { test('Apply pod-overrides sample as DevWorkspace with OC client', function (): void { kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsFile(pathToSampleFile); - ShellExecutor.wait(5); + shellExecutor.wait(5); }); test('Check that fields are overridden in the Deployment for DevWorkspace', function (): void { diff --git a/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts b/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts index b976ec3798c..36a6931289d 100644 --- a/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts +++ b/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts @@ -17,14 +17,14 @@ import { LoginTests } from '../../tests-library/LoginTests'; import { registerRunningWorkspace } from '../MochaHooks'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); - const stackName: string = 'Empty Workspace'; suite(`${stackName} test`, function (): void { + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + loginTests.loginIntoChe(); test(`Create and open new workspace, stack:${stackName}`, async function (): Promise { diff --git a/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts b/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts index 42d4b9c6ea6..acd20f07092 100644 --- a/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts +++ b/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts @@ -19,17 +19,18 @@ import { Logger } from '../../utils/Logger'; import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); - const stackName: string = 'Java 11 with Quarkus'; -const projectName: string = 'quarkus-quickstarts'; suite(`The ${stackName} userstory`, function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + let projectSection: ViewSection; + const projectName: string = 'quarkus-quickstarts'; + loginTests.loginIntoChe(); test(`Create and open new workspace, stack:${stackName}`, async function (): Promise { diff --git a/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts b/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts index 4b0dc5000c9..91ac787c26f 100644 --- a/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts +++ b/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts @@ -37,16 +37,17 @@ import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; import { PLUGIN_TEST_CONSTANTS } from '../../constants/PLUGIN_TEST_CONSTANTS'; import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); - -const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; const samples: string[] = PLUGIN_TEST_CONSTANTS.TS_SAMPLE_LIST.split(','); -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); suite(`Check if recommended extensions installed for ${samples}`, function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const cheCodeLocatorLoader: CheCodeLocatorLoader = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const webCheCodeLocators: Locators = cheCodeLocatorLoader.webCheCodeLocators; + let projectSection: ViewSection; let extensionsView: SideBarView | undefined; let extensionSection: ExtensionsViewSection; diff --git a/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts index 143881a6c4c..3b150d70e93 100644 --- a/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts +++ b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts @@ -25,18 +25,19 @@ import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -const ocpMainPage: OcpMainPage = e2eContainer.get(CLASSES.OcpMainPage); -const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); - -let ocpImportPage: OcpImportFromGitPage; -let ocpApplicationPage: OcpApplicationPage; -const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(); - suite('DevConsole Integration', function (): void { + let ocpImportPage: OcpImportFromGitPage; + let ocpApplicationPage: OcpApplicationPage; + + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const ocpMainPage: OcpMainPage = e2eContainer.get(CLASSES.OcpMainPage); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); // test specific data const gitImportRepo: string = 'https://github.com/crw-qe/summit-lab-spring-music.git'; const gitImportReference: string = 'pipeline'; diff --git a/tests/e2e/specs/factory/Factory.spec.ts b/tests/e2e/specs/factory/Factory.spec.ts index 71026663ba7..45b6d527065 100644 --- a/tests/e2e/specs/factory/Factory.spec.ts +++ b/tests/e2e/specs/factory/Factory.spec.ts @@ -28,7 +28,6 @@ import { import { expect } from 'chai'; import { OauthPage } from '../../pageobjects/git-providers/OauthPage'; import { StringUtil } from '../../utils/StringUtil'; -import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; import { registerRunningWorkspace } from '../MochaHooks'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; @@ -41,18 +40,16 @@ import { OAUTH_CONSTANTS } from '../../constants/OAUTH_CONSTANTS'; import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; import { FACTORY_TEST_CONSTANTS } from '../../constants/FACTORY_TEST_CONSTANTS'; -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); - -const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; - suite( `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository`, function (): void { - const oauthPage: OauthPage = new OauthPage(driverHelper); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const webCheCodeLocators: Locators = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const oauthPage: OauthPage = e2eContainer.get(CLASSES.OauthPage); let projectSection: ViewSection; let scmProvider: SingleScmProvider; @@ -131,7 +128,7 @@ suite( Logger.debug(`sourceControl.openView: "${viewSourceControl}"`); await sourceControl.openView(); const scmView: NewScmView = new NewScmView(); - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.inputField); [scmProvider, ...rest] = await scmView.getProviders(); Logger.debug(`scmView.getProviders: "${JSON.stringify(scmProvider)}, ${rest}"`); }); @@ -158,7 +155,6 @@ suite( }); test('Commit the changes', async function (): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); Logger.debug(`scmProvider.commitChanges: commit name "Commit ${changesToCommit}"`); await scmProvider.commitChanges('Commit ' + changesToCommit); await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); diff --git a/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts index b8c6b1e18dd..7a756f5f545 100644 --- a/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts +++ b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts @@ -45,18 +45,18 @@ import { OAUTH_CONSTANTS } from '../../constants/OAUTH_CONSTANTS'; import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; import WebDriverError = error.WebDriverError; -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; -const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); -const workspaces: Workspaces = e2eContainer.get(CLASSES.Workspaces); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); - suite( `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository without OAuth setup`, function (): void { + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + const workspaces: Workspaces = e2eContainer.get(CLASSES.Workspaces); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + let projectSection: ViewSection; let scmProvider: SingleScmProvider; let scmContextMenu: ContextMenu; @@ -173,7 +173,7 @@ suite( Logger.debug(`sourceControl.openView: "${viewSourceControl}"`); await sourceControl.openView(); const scmView: NewScmView = new NewScmView(); - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.inputField); let rest: SingleScmProvider[]; [scmProvider, ...rest] = await scmView.getProviders(); Logger.debug(`scmView.getProviders: "${JSON.stringify(scmProvider)}, ${rest}"`); @@ -201,7 +201,6 @@ suite( }); test('Commit the changes', async function (): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); Logger.debug(`scmProvider.commitChanges: commit name "Commit ${changesToCommit}"`); await scmProvider.commitChanges('Commit ' + changesToCommit); await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); diff --git a/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts index d6627e57113..2836fd756ff 100644 --- a/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts +++ b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts @@ -44,17 +44,16 @@ import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; import { FACTORY_TEST_CONSTANTS, GitProviderType } from '../../constants/FACTORY_TEST_CONSTANTS'; import WebDriverError = error.WebDriverError; -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; -const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); - suite( `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository and deny the access`, function (): void { - const oauthPage: OauthPage = new OauthPage(driverHelper); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const oauthPage: OauthPage = e2eContainer.get(CLASSES.OauthPage); let projectSection: ViewSection; let scmProvider: SingleScmProvider; @@ -170,7 +169,7 @@ suite( Logger.debug(`sourceControl.openView: "${viewSourceControl}"`); await sourceControl.openView(); const scmView: NewScmView = new NewScmView(); - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.inputField); let rest: SingleScmProvider[]; [scmProvider, ...rest] = await scmView.getProviders(); Logger.debug(`scmView.getProviders: "${JSON.stringify(scmProvider)}, ${rest}"`); @@ -198,7 +197,6 @@ suite( }); test('Commit the changes', async function (): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); Logger.debug(`scmProvider.commitChanges: commit name "Commit ${changesToCommit}"`); await scmProvider.commitChanges('Commit ' + changesToCommit); await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); diff --git a/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts b/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts index 82c358a6750..381f931c4ee 100644 --- a/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts +++ b/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts @@ -8,80 +8,76 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ import { e2eContainer } from '../../configs/inversify.config'; -import { assert } from 'chai'; +import { expect } from 'chai'; import { CLASSES } from '../../configs/inversify.types'; import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; import { Logger } from '../../utils/Logger'; import { LoginTests } from '../../tests-library/LoginTests'; import { registerRunningWorkspace } from '../MochaHooks'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ShellExecutor } from '../../utils/ShellExecutor'; -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -const util: any = require('node:util'); -const exec: any = util.promisify(require('node:child_process').exec); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const predefinedNamespaceName: string = 'predefined-ns'; +suite('Create predefined workspace and check it', function (): void { + const predefinedNamespaceName: string = 'predefined-ns'; + const stackName: string = 'Empty Workspace'; -async function runShellScript(shellCommandToExecution: string): Promise { - const { stdout, stderr } = await exec(shellCommandToExecution); - console.log(stdout); - console.error(stderr); - return stdout; -} + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); -suite('Create predefined workspace and check it ', function (): void { - let workspaceName: string = ''; - - const setEditRightsForUser: string = `oc adm policy add-role-to-user edit user -n ${predefinedNamespaceName}`; - const getDevWorkspaceFromPredefinedNameSpace: string = `oc get dw -n ${predefinedNamespaceName}`; - const deletePredefinedNamespace: string = `oc delete project ${predefinedNamespaceName}`; - const createPredefinedProjectCommand: string = - 'cat < { + suiteSetup(function (): void { + // create a predefined namespace for user using shell script and login into user dashboard Logger.info('Test prerequisites:'); Logger.info( ' (1) there is OCP user with username and user password that have been set in the TS_SELENIUM_OCP_USERNAME and TS_SELENIUM_OCP_PASSWORD variables' ); Logger.info(' (2) "oc" client installed and logged into test OCP cluster with admin rights.'); - - await runShellScript(createPredefinedProjectCommand); - await runShellScript(setEditRightsForUser); + kubernetesCommandLineToolsExecutor.loginToOcp('admin'); + const predefinedProjectConfiguration: string = + 'kind: Namespace\n' + + 'apiVersion: v1\n' + + 'metadata:\n' + + ` name: ${predefinedNamespaceName}\n` + + ' labels:\n' + + ' app.kubernetes.io/part-of: che.eclipse.org\n' + + ' app.kubernetes.io/component: workspaces-namespace\n' + + ' annotations:\n' + + ' che.eclipse.org/username: user'; + kubernetesCommandLineToolsExecutor.applyWithoutNamespace(predefinedProjectConfiguration); + const setEditRightsForUser: string = `oc adm policy add-role-to-user edit user -n ${predefinedNamespaceName}`; + shellExecutor.executeCommand(setEditRightsForUser); }); - suiteTeardown(async (): Promise => { + suiteTeardown(function (): void { const workspaceName: string = WorkspaceHandlingTests.getWorkspaceName(); try { - await runShellScript(deletePredefinedNamespace); + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + kubernetesCommandLineToolsExecutor.deleteProject(predefinedNamespaceName); } catch (e) { Logger.error(`Cannot remove the predefined project: ${workspaceName}, please fix it manually: ${e}`); } }); - loginTests.loginIntoChe(); + loginTests.loginIntoChe('user'); // create the Empty workspace using CHE Dashboard - test(`Create and open new workspace, stack:${'Empty Workspace'}`, async function (): Promise { - await workspaceHandlingTests.createAndOpenWorkspace('Empty Workspace'); + test(`Create and open new workspace, stack:${stackName}`, async function (): Promise { + await workspaceHandlingTests.createAndOpenWorkspace(stackName); }); test('Obtain workspace name from workspace loader page', async function (): Promise { await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); }); // verify that just created workspace with unique name is present in the predefined namespace - test('Validate the created workspace is present in predefined namespace', async function (): Promise { - workspaceName = WorkspaceHandlingTests.getWorkspaceName(); + test('Validate the created workspace is present in predefined namespace', function (): void { + const workspaceName: string = WorkspaceHandlingTests.getWorkspaceName(); registerRunningWorkspace(workspaceName); - const ocDevWorkspaceOutput: string = await runShellScript(getDevWorkspaceFromPredefinedNameSpace); - assert.isTrue(ocDevWorkspaceOutput.includes(workspaceName)); + kubernetesCommandLineToolsExecutor.workspaceName = workspaceName; + kubernetesCommandLineToolsExecutor.namespace = predefinedNamespaceName; + const ocDevWorkspaceOutput: string = kubernetesCommandLineToolsExecutor.getDevWorkspaceYamlConfiguration(); + expect(ocDevWorkspaceOutput).includes(workspaceName); }); loginTests.logoutFromChe(); diff --git a/tests/e2e/tests-library/LoginTests.ts b/tests/e2e/tests-library/LoginTests.ts index 2a6fc8534ac..196856cd8f5 100644 --- a/tests/e2e/tests-library/LoginTests.ts +++ b/tests/e2e/tests-library/LoginTests.ts @@ -27,12 +27,12 @@ export class LoginTests { @inject(CLASSES.Dashboard) private readonly dashboard: Dashboard ) {} - loginIntoChe(): void { + loginIntoChe(userName?: string, password?: string): void { test('Login', async (): Promise => { if (!(await this.browserTabsUtil.getCurrentUrl()).includes(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL)) { await this.browserTabsUtil.navigateTo(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL); } - await this.productLoginPage.login(); + await this.productLoginPage.login(userName, password); await this.browserTabsUtil.maximize(); await this.dashboard.waitStartingPageLoaderDisappearance(); }); @@ -42,7 +42,7 @@ export class LoginTests { test('Login into ocp console', async (): Promise => { const openshiftConsoleUrl: string = BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL.replace('devspaces', 'console-openshift-console'); await this.browserTabsUtil.navigateTo(openshiftConsoleUrl); - this.ocpLoginPage.login(); + await this.ocpLoginPage.login(); await this.browserTabsUtil.maximize(); }); } diff --git a/tests/e2e/tests-library/WorkspaceHandlingTests.ts b/tests/e2e/tests-library/WorkspaceHandlingTests.ts index 2e41c67f262..cd96c54fb20 100644 --- a/tests/e2e/tests-library/WorkspaceHandlingTests.ts +++ b/tests/e2e/tests-library/WorkspaceHandlingTests.ts @@ -22,7 +22,7 @@ import { By, error } from 'selenium-webdriver'; @injectable() export class WorkspaceHandlingTests { - private static WORKSPACE_NAME_LOCATOR: By = By.xpath('//h1[contains(.,"Starting workspace ")]'); + private static WORKSPACE_NAME: By = By.xpath('//h1[contains(.,"Starting workspace ")]'); private static workspaceName: string = 'undefined'; private static parentGUID: string; @@ -82,7 +82,7 @@ export class WorkspaceHandlingTests { try { const startingWorkspaceLineContent: string = await this.driverHelper .getDriver() - .findElement(WorkspaceHandlingTests.WORKSPACE_NAME_LOCATOR) + .findElement(WorkspaceHandlingTests.WORKSPACE_NAME) .getText(); Logger.trace(`obtained starting workspace getText():${startingWorkspaceLineContent}`); // cutting away leading text diff --git a/tests/e2e/utils/BrowserTabsUtil.ts b/tests/e2e/utils/BrowserTabsUtil.ts index 93b304b34da..a38c5890232 100644 --- a/tests/e2e/utils/BrowserTabsUtil.ts +++ b/tests/e2e/utils/BrowserTabsUtil.ts @@ -12,7 +12,6 @@ import { inject, injectable } from 'inversify'; import { CLASSES } from '../configs/inversify.types'; import { DriverHelper } from './DriverHelper'; import { Logger } from './Logger'; -import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; @injectable() @@ -24,6 +23,7 @@ export class BrowserTabsUtil { async switchToWindow(windowHandle: string): Promise { Logger.debug(); + await this.driverHelper.getDriver().switchTo().window(windowHandle); } @@ -42,14 +42,7 @@ export class BrowserTabsUtil { async navigateTo(url: string): Promise { Logger.debug(`${url}`); - await this.driverHelper.getDriver().navigate().to(url); - } - - async navigateAndWaitToUrl(url: string, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL): Promise { - Logger.trace(`${url}`); - - await this.navigateTo(url); - await this.waitURL(url, timeout); + await this.driverHelper.navigateToUrl(url); } async waitAndSwitchToAnotherWindow(currentWindowHandle: string, timeout: number): Promise { @@ -77,11 +70,14 @@ export class BrowserTabsUtil { } async getCurrentUrl(): Promise { + Logger.trace(); + return await this.driverHelper.getDriver().getCurrentUrl(); } async waitURL(expectedUrl: string, timeout: number): Promise { Logger.trace(`${expectedUrl}`); + try { await this.driverHelper.getDriver().wait(async (): Promise => { const currentUrl: string = await this.driverHelper.getDriver().getCurrentUrl(); @@ -98,6 +94,7 @@ export class BrowserTabsUtil { async maximize(): Promise { Logger.trace(); + if (CHROME_DRIVER_CONSTANTS.TS_SELENIUM_LAUNCH_FULLSCREEN) { Logger.debug('TS_SELENIUM_LAUNCH_FULLSCREEN is set to true, maximizing window.'); await this.driverHelper.getDriver().manage().window().maximize(); @@ -106,6 +103,7 @@ export class BrowserTabsUtil { async closeAllTabsExceptCurrent(): Promise { Logger.trace(); + const allTabsHandles: string[] = await this.getAllWindowHandles(); const currentTabHandle: string = await this.getCurrentWindowHandle(); allTabsHandles.splice(allTabsHandles.indexOf(currentTabHandle), 1); diff --git a/tests/e2e/utils/CheReporter.ts b/tests/e2e/utils/CheReporter.ts index 4bc9a4c01b9..f33005b39dc 100644 --- a/tests/e2e/utils/CheReporter.ts +++ b/tests/e2e/utils/CheReporter.ts @@ -17,21 +17,27 @@ import { DriverHelper } from './DriverHelper'; import { ScreenCatcher } from './ScreenCatcher'; import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; import { Logger } from './Logger'; -import { e2eContainer } from '../configs/inversify.config'; import { StringUtil } from './StringUtil'; import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; import { OAUTH_CONSTANTS } from '../constants/OAUTH_CONSTANTS'; import { REPORTER_CONSTANTS } from '../constants/REPORTER_CONSTANTS'; import { PLUGIN_TEST_CONSTANTS } from '../constants/PLUGIN_TEST_CONSTANTS'; +import { inject, injectable } from 'inversify'; -const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const screenCatcher: ScreenCatcher = e2eContainer.get(CLASSES.ScreenCatcher); -let methodIndex: number = 0; -let deleteScreencast: boolean = true; - +@injectable() class CheReporter extends mocha.reporters.Spec { - constructor(runner: mocha.Runner, options: mocha.MochaOptions) { + private static methodIndex: number = 0; + private static deleteScreencast: boolean = true; + + constructor( + runner: mocha.Runner, + options: mocha.MochaOptions, + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper, + @inject(CLASSES.ScreenCatcher) + private readonly screenCatcher: ScreenCatcher + ) { super(runner, options); runner.on('start', (): void => { @@ -76,20 +82,20 @@ class CheReporter extends mocha.reporters.Spec { rm.sync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); }); - runner.on('test', async function (test: mocha.Test): Promise { + runner.on('test', async (test: mocha.Test): Promise => { if (!REPORTER_CONSTANTS.TS_SELENIUM_EXECUTION_SCREENCAST) { return; } - methodIndex = methodIndex + 1; - const currentMethodIndex: number = methodIndex; + CheReporter.methodIndex = CheReporter.methodIndex + 1; + const currentMethodIndex: number = CheReporter.methodIndex; let iterationIndex: number = 1; while (!(test.state === 'passed' || test.state === 'failed')) { - await screenCatcher.catchMethodScreen(test.title, currentMethodIndex, iterationIndex); + await this.screenCatcher.catchMethodScreen(test.title, currentMethodIndex, iterationIndex); iterationIndex = iterationIndex + 1; - await driverHelper.wait(REPORTER_CONSTANTS.TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS); + await this.driverHelper.wait(REPORTER_CONSTANTS.TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS); } }); @@ -107,21 +113,21 @@ class CheReporter extends mocha.reporters.Spec { runner.on('end', async (): Promise => { // ensure that fired events done - await driverHelper.wait(5000); + await this.driverHelper.wait(5000); // close driver - await driverHelper.getDriver().quit(); + await this.driverHelper.getDriver().quit(); // delete screencast folder if conditions matched - if (deleteScreencast && REPORTER_CONSTANTS.DELETE_SCREENCAST_IF_TEST_PASS) { + if (CheReporter.deleteScreencast && REPORTER_CONSTANTS.DELETE_SCREENCAST_IF_TEST_PASS) { rm.sync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); } }); - runner.on('fail', async function (test: mocha.Test): Promise { + runner.on('fail', async (test: mocha.Test): Promise => { Logger.error(`CheReporter runner.on.fail: ${test.fullTitle()} failed after ${test.duration}ms`); // raise flag for keeping the screencast - deleteScreencast = false; + CheReporter.deleteScreencast = false; Logger.trace(`FullTitle:${test.fullTitle()}`); const testFullTitle: string = StringUtil.sanitizeTitle(test.fullTitle()); @@ -150,19 +156,19 @@ class CheReporter extends mocha.reporters.Spec { } // take screenshot and write to file - const screenshot: string = await driverHelper.getDriver().takeScreenshot(); + const screenshot: string = await this.driverHelper.getDriver().takeScreenshot(); const screenshotStream: WriteStream = fs.createWriteStream(screenshotFileName); screenshotStream.write(Buffer.from(screenshot, 'base64')); screenshotStream.end(); // take page source and write to file - const pageSource: string = await driverHelper.getDriver().getPageSource(); + const pageSource: string = await this.driverHelper.getDriver().getPageSource(); const pageSourceStream: WriteStream = fs.createWriteStream(pageSourceFileName); pageSourceStream.write(Buffer.from(pageSource)); pageSourceStream.end(); // take browser console logs and write to file - const browserLogsEntries: logging.Entry[] = await driverHelper.getDriver().manage().logs().get('browser'); + const browserLogsEntries: logging.Entry[] = await this.driverHelper.getDriver().manage().logs().get('browser'); let browserLogs: string = ''; browserLogsEntries.forEach((log): void => { diff --git a/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts b/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts index 59fe1dc5812..1a56e55e154 100644 --- a/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts +++ b/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts @@ -15,31 +15,16 @@ import * as axios from 'axios'; import { Logger } from './Logger'; import { ShellExecutor } from './ShellExecutor'; import { API_TEST_CONSTANTS } from '../constants/API_TEST_CONSTANTS'; +import { injectable } from 'inversify'; +import { IContextParams } from './IContextParams'; +import { e2eContainer } from '../configs/inversify.config'; +import { CLASSES, EXTERNAL_CLASSES } from '../configs/inversify.types'; -/** - * to see more about IContextParams and generateDevfileContext(params) check README.md in "@eclipse-che/che-devworkspace-generator; - * tests/e2e/node_modules/@eclipse-che/che-devworkspace-generator/README.md - */ - -interface IContextParams { - devfilePath?: string | undefined; - devfileUrl?: string | undefined; - devfileContent?: string | undefined; - outputFile?: string | undefined; - editorPath?: string | undefined; - editorContent?: string | undefined; - editorEntry?: string | undefined; - pluginRegistryUrl?: string | undefined; - projects?: { - name: string; - location: string; - }[]; - injectDefaultComponent?: string | undefined; - defaultComponentImage?: string | undefined; -} - +@injectable() export class DevWorkspaceConfigurationHelper { - private generator: Generator = new Generator(); + private generator: Generator = e2eContainer.get(EXTERNAL_CLASSES.Generator); + private shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); + private readonly params: IContextParams; constructor(params: IContextParams) { @@ -60,7 +45,7 @@ export class DevWorkspaceConfigurationHelper { params.pluginRegistryUrl = API_TEST_CONSTANTS.TS_API_TEST_PLUGIN_REGISTRY_URL; } if (API_TEST_CONSTANTS.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI && !params.editorContent) { - params.editorContent = ShellExecutor.curl(API_TEST_CONSTANTS.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI).stdout; + params.editorContent = this.shellExecutor.curl(API_TEST_CONSTANTS.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI).stdout; } this.params = params; } diff --git a/tests/e2e/utils/DevfilesRegistryHelper.ts b/tests/e2e/utils/DevfilesRegistryHelper.ts index 3e8731e7e07..5cf1cb80876 100644 --- a/tests/e2e/utils/DevfilesRegistryHelper.ts +++ b/tests/e2e/utils/DevfilesRegistryHelper.ts @@ -11,20 +11,25 @@ import axios, { AxiosResponse } from 'axios'; import { Logger } from './Logger'; import YAML from 'yaml'; import { API_TEST_CONSTANTS, SUPPORTED_DEVFILE_REGISTRIES } from '../constants/API_TEST_CONSTANTS'; +import { injectable } from 'inversify'; +@injectable() export class DevfilesRegistryHelper { async getInbuiltDevfilesRegistryContent(): Promise { - Logger.debug(); + Logger.trace(); + return await this.getContent(SUPPORTED_DEVFILE_REGISTRIES.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL()); } async getGitHubCheDevfileRegistryContent(): Promise { - Logger.debug(); + Logger.trace(); + return await this.getContent(SUPPORTED_DEVFILE_REGISTRIES.GIT_HUB_CHE_DEVFILE_REGISTRY_URL); } async collectPathsToDevfilesFromRegistry(): Promise { Logger.debug(); + const devfileSamples: object[] = []; const sampleNames: string[] = []; switch (API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL()) { @@ -72,7 +77,7 @@ export class DevfilesRegistryHelper { } private async getContent(url: string, headers?: object): Promise { - Logger.debug(`${url}`); + Logger.trace(`${url}`); let response: AxiosResponse | undefined; try { diff --git a/tests/e2e/utils/DriverHelper.ts b/tests/e2e/utils/DriverHelper.ts index 94c29310c08..b62053e00ec 100644 --- a/tests/e2e/utils/DriverHelper.ts +++ b/tests/e2e/utils/DriverHelper.ts @@ -95,7 +95,6 @@ export class DriverHelper { async waitVisibility(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator}`); for (let i: number = 0; i < attempts; i++) { @@ -158,7 +157,6 @@ export class DriverHelper { async waitPresence(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator}`); for (let i: number = 0; i < attempts; i++) { @@ -191,7 +189,6 @@ export class DriverHelper { ): Promise> { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator}`); for (let i: number = 0; i < attempts; i++) { @@ -246,6 +243,7 @@ export class DriverHelper { pollingPerLocator: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING ): Promise { Logger.trace(`${locators}`); + try { for (const elementLocator of locators) { await this.waitDisappearance(elementLocator, attemptsPerLocator, pollingPerLocator); @@ -258,7 +256,6 @@ export class DriverHelper { async waitAndClick(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator}`); for (let i: number = 0; i < attempts; i++) { @@ -284,7 +281,7 @@ export class DriverHelper { await element.click(); return; } catch (err) { - function isElementClickInterceptedOnLastAttempt(err: Error, i: number): boolean { + function isElementClickInterceptedOnLastAttempt(err: any, i: number): boolean { return err instanceof error.ElementClickInterceptedError && i === attempts - 1; } @@ -320,7 +317,6 @@ export class DriverHelper { ): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator} attribute: '${attribute}'`); for (let i: number = 0; i < attempts; i++) { @@ -367,7 +363,6 @@ export class DriverHelper { ): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator} cssAttribute: ${cssAttribute}`); for (let i: number = 0; i < attempts; i++) { @@ -474,7 +469,6 @@ export class DriverHelper { ): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator} text: ${text}`); for (let i: number = 0; i < attempts; i++) { @@ -516,7 +510,6 @@ export class DriverHelper { async clear(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator}`); for (let i: number = 0; i < attempts; i++) { @@ -558,7 +551,6 @@ export class DriverHelper { async clearInvisible(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator}`); for (let i: number = 0; i < attempts; i++) { @@ -624,7 +616,6 @@ export class DriverHelper { async waitAndGetText(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator}`); for (let i: number = 0; i < attempts; i++) { @@ -677,7 +668,6 @@ export class DriverHelper { async scrollTo(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); - Logger.trace(`${elementLocator}`); for (let i: number = 0; i < attempts; i++) { @@ -717,6 +707,8 @@ export class DriverHelper { } async scrollToAndClick(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + Logger.trace(); + await this.scrollTo(elementLocator, timeout); await this.waitAndClick(elementLocator, timeout); } @@ -726,12 +718,16 @@ export class DriverHelper { value: string, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM ): Promise { + Logger.trace(); + await this.scrollTo(elementLocator, timeout); await this.enterValue(elementLocator, value, timeout); } // method is useful to debug page object elements async highLightElement(element: WebElement): Promise { + Logger.trace(); + await this.getDriver().executeScript('arguments[0].style.border="2px solid red"', element); } @@ -740,4 +736,10 @@ export class DriverHelper { return this.driver; } + + async navigateToUrl(url: string): Promise { + Logger.trace(); + + await this.getDriver().navigate().to(url); + } } diff --git a/tests/e2e/utils/IContextParams.ts b/tests/e2e/utils/IContextParams.ts new file mode 100644 index 00000000000..22e8dfbf3f3 --- /dev/null +++ b/tests/e2e/utils/IContextParams.ts @@ -0,0 +1,26 @@ +/** ******************************************************************* + * copyright (c) 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 + **********************************************************************/ + +export interface IContextParams { + devfilePath?: string | undefined; + devfileUrl?: string | undefined; + devfileContent?: string | undefined; + outputFile?: string | undefined; + editorPath?: string | undefined; + editorContent?: string | undefined; + editorEntry?: string | undefined; + pluginRegistryUrl?: string | undefined; + projects?: { + name: string; + location: string; + }[]; + injectDefaultComponent?: string | undefined; + defaultComponentImage?: string | undefined; +} diff --git a/tests/e2e/utils/IKubernetesCommandLineToolsExecutor.ts b/tests/e2e/utils/IKubernetesCommandLineToolsExecutor.ts new file mode 100644 index 00000000000..fc5867f43ce --- /dev/null +++ b/tests/e2e/utils/IKubernetesCommandLineToolsExecutor.ts @@ -0,0 +1,42 @@ +/** ******************************************************************* + * copyright (c) 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 { ShellString } from 'shelljs'; + +export interface IKubernetesCommandLineToolsExecutor { + loginToOcp(): void; + + getContainerName(): string; + + getWorkspacePodName(): string; + + deleteDevWorkspace(): void; + + applyAndWaitDevWorkspace(yamlConfiguration: string): ShellString; + + executeCommand(commandToExecute: string, container: string): ShellString; + + applyYamlConfigurationAsStringOutput(yamlConfiguration: string): ShellString; + + applyYamlConfigurationAsFile(pathToFile: string): void; + + getDevWorkspaceYamlConfiguration(): ShellString; + + waitDevWorkspace(timeout: number): ShellString; + + createProject(projectName: string): void; + + deleteProject(projectName: string): void; + + getPodAndContainerNames(): void; + + isUserLoggedIn(user: string): boolean; + + getServerUrl(): string; +} diff --git a/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts b/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts index 5e81c96d474..67f711ee727 100644 --- a/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts +++ b/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts @@ -14,76 +14,100 @@ import * as path from 'path'; import { API_TEST_CONSTANTS, KubernetesCommandLineTool } from '../constants/API_TEST_CONSTANTS'; import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; import { OAUTH_CONSTANTS } from '../constants/OAUTH_CONSTANTS'; +import { IKubernetesCommandLineToolsExecutor } from './IKubernetesCommandLineToolsExecutor'; +import { inject, injectable } from 'inversify'; +import { CLASSES } from '../configs/inversify.types'; -export class KubernetesCommandLineToolsExecutor extends ShellExecutor { +@injectable() +export class KubernetesCommandLineToolsExecutor implements IKubernetesCommandLineToolsExecutor { private static container: string; private static pod: string; - private readonly namespace: string; - private readonly workspaceName: string | undefined; - private readonly KUBERNETES_COMMAND_LINE_TOOL: string = API_TEST_CONSTANTS.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL; + private readonly kubernetesCommandLineTool: string; + protected _namespace: string | undefined; + protected _workspaceName: string | undefined; - constructor(_workspaceName?: string, _namespace?: string) { - super(); - this.workspaceName = _workspaceName; - this.namespace = this.setNamespace(_namespace); + constructor( + @inject(CLASSES.ShellExecutor) + protected readonly shellExecutor: ShellExecutor + ) { + this.kubernetesCommandLineTool = API_TEST_CONSTANTS.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL; } - get getWorkspaceName(): string { - return this.workspaceName; + set namespace(value: string | undefined) { + this._namespace = value; } - get getNamespace(): string { - return this.namespace; + set workspaceName(value: string | undefined) { + this._workspaceName = value; + } + + get workspaceName(): string | undefined { + return this._workspaceName; + } + + get namespace(): string | undefined { + this._namespace = + this._namespace !== undefined + ? this._namespace + : BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL.includes('devspaces') + ? OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME + '-devspaces' + : BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL.includes('che') + ? OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME + '-che' + : 'default'; + return this._namespace; } // login to Openshift cluster with username and password - loginToOcp(): void { - if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.OC) { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - login to the "OC" client.`); + loginToOcp(user: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME, password: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD): void { + if (this.kubernetesCommandLineTool === KubernetesCommandLineTool.OC) { + Logger.debug(`${this.kubernetesCommandLineTool} - login to the "OC" client.`); const url: string = this.getServerUrl(); - if (this.isUserLoggedIn()) { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - user already logged`); + if (this.isUserLoggedIn(user)) { + Logger.debug(`${this.kubernetesCommandLineTool} - user already logged`); } else { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - login ${url}, ${OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME}`); - exec( - `oc login --server=${url} -u=${OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME} -p=${OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD} --insecure-skip-tls-verify` - ); + Logger.debug(`${this.kubernetesCommandLineTool} - login ${url}, ${user}`); + exec(`oc login --server=${url} -u=${user} -p=${password} --insecure-skip-tls-verify`); } } else { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - doesn't support login command`); + Logger.debug(`${this.kubernetesCommandLineTool} - doesn't support login command`); } } getContainerName(): string { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - get container name.`); - const output: ShellString = ShellExecutor.execWithLog( - `${this.KUBERNETES_COMMAND_LINE_TOOL} get ${KubernetesCommandLineToolsExecutor.pod} -o jsonpath='{.spec.containers[*].name}' -n ${this.namespace}` + Logger.debug(`${this.kubernetesCommandLineTool} - get container name.`); + + const output: ShellString = this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} get ${KubernetesCommandLineToolsExecutor.pod} -o jsonpath='{.spec.containers[*].name}' -n ${this.namespace}` ); echo('\n'); return output.stderr ? output.stderr : output.stdout; } getWorkspacePodName(): string { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - get workspace pod name.`); - const output: ShellString = ShellExecutor.execWithLog( - `${this.KUBERNETES_COMMAND_LINE_TOOL} get pod -l controller.devfile.io/devworkspace_name=${this.workspaceName} -n ${this.namespace} -o name` + Logger.debug(`${this.kubernetesCommandLineTool} - get workspace pod name.`); + + const output: ShellString = this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} get pod -l controller.devfile.io/devworkspace_name=${this.workspaceName} -n ${this.namespace} -o name` ); return output.stderr ? output.stderr : output.stdout.replace('\n', ''); } deleteDevWorkspace(): void { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - delete '${this.workspaceName}' workspace`); - ShellExecutor.execWithLog( - `${this.KUBERNETES_COMMAND_LINE_TOOL} patch dw ${this.workspaceName} -n ${this.namespace} -p '{ "metadata": { "finalizers": null }}' --type merge || true` + Logger.debug(`${this.kubernetesCommandLineTool} - delete '${this.workspaceName}' workspace`); + + this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} patch dw ${this.workspaceName} -n ${this.namespace} -p '{ "metadata": { "finalizers": null }}' --type merge || true` ); - ShellExecutor.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} delete dw ${this.workspaceName} -n ${this.namespace} || true`); - ShellExecutor.execWithLog( - `${this.KUBERNETES_COMMAND_LINE_TOOL} delete dwt ${BASE_TEST_CONSTANTS.TS_SELENIUM_EDITOR}-${this.workspaceName} -n ${this.namespace} || true` + this.shellExecutor.executeCommand(`${this.kubernetesCommandLineTool} delete dw ${this.workspaceName} -n ${this.namespace} || true`); + this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} delete dwt ${BASE_TEST_CONSTANTS.TS_SELENIUM_EDITOR}-${this.workspaceName} -n ${this.namespace} || true` ); } applyAndWaitDevWorkspace(yamlConfiguration: string): ShellString { - if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.KUBECTL) { + Logger.debug(`${this.kubernetesCommandLineTool}`); + + if (this.kubernetesCommandLineTool === KubernetesCommandLineTool.KUBECTL) { this.createNamespace(); } this.applyYamlConfigurationAsStringOutput(yamlConfiguration); @@ -91,116 +115,124 @@ export class KubernetesCommandLineToolsExecutor extends ShellExecutor { } executeCommand(commandToExecute: string, container: string = KubernetesCommandLineToolsExecutor.container): ShellString { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL}`); - return ShellExecutor.execWithLog( - `${this.KUBERNETES_COMMAND_LINE_TOOL} exec -i ${KubernetesCommandLineToolsExecutor.pod} -n ${this.namespace} -c ${container} -- sh -c '${commandToExecute}'` + Logger.debug(`${this.kubernetesCommandLineTool}`); + + return this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} exec -i ${KubernetesCommandLineToolsExecutor.pod} -n ${this.namespace} -c ${container} -- sh -c '${commandToExecute}'` ); } applyYamlConfigurationAsStringOutput(yamlConfiguration: string): ShellString { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL}`); - return ShellExecutor.execWithLog( - `cat <