From ba34736f298bf26aa9500771c018f8e80b8e23f9 Mon Sep 17 00:00:00 2001 From: Maryna Dolhalova Date: Fri, 24 Mar 2023 16:41:02 +0100 Subject: [PATCH] Move Dev Spaces typescript functional tests, clean up outdated code --- tests/e2e/README.md | 43 +-- tests/e2e/configs/inversify.config.ts | 22 +- tests/e2e/configs/inversify.types.ts | 35 +-- tests/e2e/configs/mocharc.ts | 4 +- tests/e2e/constants/TestConstants.ts | 111 ++++--- .../plugins/GitHubPullRequestPlugin.yaml | 11 - .../plugins/InstallPluginUsingUI.yaml | 3 - .../devfiles/plugins/Java11PluginTest.yaml | 17 -- .../files/devfiles/plugins/PhpPluginTest.yaml | 47 --- .../devfiles/plugins/PythonPluginTest.yaml | 14 - .../TypescriptNodeDebug2PluginTest.yaml | 49 ---- .../plugins/VscodeKubernetesPlugin.yaml | 12 - .../plugins/VscodeShellcheckPlugin.yaml | 12 - .../devfiles/plugins/VscodeValePlugin.yaml | 42 --- .../devfiles/plugins/VscodeXmlPlugin.yaml | 12 - .../devfiles/plugins/VscodeYamlPlugin.yaml | 12 - .../happy-path/containers-happy-path.yaml | 127 -------- .../happy-path/happy-path-workspace.yaml | 95 ------ .../files/happy-path/petclinic-classpath.txt | 49 ---- tests/e2e/index.ts | 39 +++ tests/e2e/package-lock.json | 187 +++++++++++- tests/e2e/package.json | 14 +- .../pageobjects/dashboard/CreateWorkspace.ts | 8 - tests/e2e/pageobjects/dashboard/Dashboard.ts | 12 +- tests/e2e/pageobjects/dashboard/Workspaces.ts | 4 +- .../WorkspaceDetailsPlugins.ts | 95 ------ .../pageobjects/git-providers/OauthPage.ts | 156 ++++++++++ .../pageobjects/ide/CheCodeLocatorLoader.ts | 73 +++++ .../pageobjects/login/OcpRedHatLoginPage.ts | 49 ++++ .../e2e/pageobjects/login/RedHatLoginPage.ts | 62 ++++ .../login/RegularUserOcpCheLoginPage.ts | 9 +- .../e2e/pageobjects/openshift/CheLoginPage.ts | 4 +- .../e2e/pageobjects/openshift/OcpLoginPage.ts | 21 -- .../pageobjects/third-parties/GitLoginPage.ts | 81 ------ .../third-parties/GitOauthAppsSettings.ts | 110 ------- tests/e2e/specs/MochaHooks.ts | 4 +- .../e2e/specs/devfiles/EmptyWorkspace.spec.ts | 1 + tests/e2e/specs/devfiles/Quarkus.spec.ts | 52 ++++ tests/e2e/specs/factory/Factory.spec.ts | 199 +++++++++++++ .../specs/factory/NoSetupRepoFactory.spec.ts | 272 ++++++++++++++++++ .../specs/factory/RefusedOAuthFactory.spec.ts | 260 +++++++++++++++++ .../specs/login/LinkCheAndOcpUsers.spec.ts | 49 ---- .../miscellaneous/PredefinedNamespace.spec.ts | 74 +++++ tests/e2e/tests-library/LoginTests.ts | 10 +- .../tests-library/WorkspaceHandlingTests.ts | 4 - tests/e2e/utils/BrowserTabsUtil.ts | 26 +- tests/e2e/utils/DriverHelper.ts | 93 +----- tests/e2e/utils/Logger.ts | 5 + tests/e2e/utils/Sanitizer.ts | 1 - tests/e2e/utils/WorkspaceNameHandler.ts | 48 ---- .../request-handlers/CheApiRequestHandler.ts | 2 +- .../tokens/CheMultiuserTokenHandler.ts | 41 --- .../request-handlers/tokens/ITokenHandler.ts | 14 - tests/e2e/utils/vsc/CheGitApi.ts | 22 -- tests/e2e/utils/vsc/GitUtil.ts | 28 ++ tests/e2e/utils/vsc/github/GitHubUtil.ts | 110 ------- tests/e2e/utils/workspace/ApiUrlResolver.ts | 4 - .../e2e/utils/workspace/ITestWorkspaceUtil.ts | 57 +--- .../e2e/utils/workspace/TestWorkspaceUtil.ts | 245 +--------------- 59 files changed, 1578 insertions(+), 1684 deletions(-) delete mode 100644 tests/e2e/files/devfiles/plugins/GitHubPullRequestPlugin.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/InstallPluginUsingUI.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/Java11PluginTest.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/PhpPluginTest.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/PythonPluginTest.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/TypescriptNodeDebug2PluginTest.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/VscodeKubernetesPlugin.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/VscodeShellcheckPlugin.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/VscodeValePlugin.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/VscodeXmlPlugin.yaml delete mode 100644 tests/e2e/files/devfiles/plugins/VscodeYamlPlugin.yaml delete mode 100644 tests/e2e/files/happy-path/containers-happy-path.yaml delete mode 100644 tests/e2e/files/happy-path/happy-path-workspace.yaml delete mode 100644 tests/e2e/files/happy-path/petclinic-classpath.txt create mode 100644 tests/e2e/index.ts delete mode 100644 tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetailsPlugins.ts create mode 100644 tests/e2e/pageobjects/git-providers/OauthPage.ts create mode 100644 tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts create mode 100644 tests/e2e/pageobjects/login/OcpRedHatLoginPage.ts create mode 100644 tests/e2e/pageobjects/login/RedHatLoginPage.ts delete mode 100644 tests/e2e/pageobjects/third-parties/GitLoginPage.ts delete mode 100644 tests/e2e/pageobjects/third-parties/GitOauthAppsSettings.ts create mode 100644 tests/e2e/specs/devfiles/Quarkus.spec.ts create mode 100644 tests/e2e/specs/factory/Factory.spec.ts create mode 100644 tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts create mode 100644 tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts delete mode 100644 tests/e2e/specs/login/LinkCheAndOcpUsers.spec.ts create mode 100644 tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts delete mode 100644 tests/e2e/utils/WorkspaceNameHandler.ts delete mode 100644 tests/e2e/utils/request-handlers/tokens/CheMultiuserTokenHandler.ts delete mode 100644 tests/e2e/utils/request-handlers/tokens/ITokenHandler.ts delete mode 100644 tests/e2e/utils/vsc/CheGitApi.ts create mode 100644 tests/e2e/utils/vsc/GitUtil.ts delete mode 100644 tests/e2e/utils/vsc/github/GitHubUtil.ts diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 64ea4744783e..a4052bc5f615 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -3,8 +3,8 @@ ## Requirements -- node 8.x -- "Chrome" browser 69.x or later +- node 16.x +- "Chrome" browser 111.x or later - deployed Che 7 with accessible URL ## Before launch @@ -21,13 +21,14 @@ Note: If there is any modifications in package.json, manually execute the `npm i - Provide connection credentials to Che: - ```export TS_SELENIUM_USERNAME=``` - ```export TS_SELENIUM_PASSWORD=``` -- ```npm test``` + - ```npm run test-regression``` ## Custom launch - Use environment variables which described in the **```'TestConstants.ts'```** file - Use environment variables for setting timeouts if needed. You can see the list in **```'TimeoutConstants.ts'```**. You can see the list of those variables and their value if you set the ```'TS_SELENIUM_PRINT_TIMEOUT_VARIABLES = true'``` -- Check for available scripts in package.json which are prefixed by `test-`. Then, perform command ```npm run test-``` +- To test one specification export file name as ```export USERSTORY=``` and run script ```npm run test-userstory``` +- To test all specification in folder ```export MOCHA_DIRECTORY=``` and run script ```npm run test-suite``` ## Docker launch @@ -58,35 +59,8 @@ For running tests without docker, please perform next steps:** - link to devfile ( **```For successfull test passing, exactly provided devfile should be used```** ) - Provide the **```'TS_SELENIUM_BASE_URL'```** environment variable as described above -- perform command **```'npm run test-happy-path'```** - -## Plugins tests launching for the Che without oauth authentication - -**Setup next environment variables:** - -- export TS_SELENIUM_BASE_URL=\ -- export USERSTORY=\ -- (skip if login is "admin") export TS_SELENIUM_USERNAME=\ -- (skip if password is "admin") export TS_SELENIUM_PASSWORD=\ - -**Run command:** - -- npm run test-plugin - -## Plugins tests launching for the Che with oauth authentication - -**Setup next environment variables:** - -- export TS_SELENIUM_BASE_URL=\ -- export USERSTORY=\ -- export TS_SELENIUM_VALUE_OPENSHIFT_OAUTH="true" -- export TS_SELENIUM_OCP_USERNAME=\ -- export TS_SELENIUM_OCP_PASSWORD=\ - -**Run command:** - -- npm run test-plugin - +- export TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME=EmptyWorkspace (default value, see TestConstants.ts) +- perform command **```export USERSTORY=$TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME && npm run test-all-devfiles```** ## Launching the DevWorkspaceHappyPath spec file using Che with oauth authentication @@ -98,6 +72,7 @@ For running tests without docker, please perform next steps:** - export TS_SELENIUM_VALUE_OPENSHIFT_OAUTH="true" - export TS_OCP_LOGIN_PAGE_PROVIDER_TITLE=\ - export TS_SELENIUM_DEVWORKSPACE_URL=\ +- export TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME=EmptyWorkspace (default value, see TestConstants.ts) **Execute the npm command:** -- npm run test-devworkspace-happy-path +- perform command ```export USERSTORY=$TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME && npm run test-all-devfiles``` diff --git a/tests/e2e/configs/inversify.config.ts b/tests/e2e/configs/inversify.config.ts index 230126e069eb..89e6f6996930 100644 --- a/tests/e2e/configs/inversify.config.ts +++ b/tests/e2e/configs/inversify.config.ts @@ -24,29 +24,23 @@ import { DriverHelper } from '../utils/DriverHelper'; import { Dashboard } from '../pageobjects/dashboard/Dashboard'; import { Workspaces } from '../pageobjects/dashboard/Workspaces'; import { WorkspaceDetails } from '../pageobjects/dashboard/workspace-details/WorkspaceDetails'; -import { WorkspaceDetailsPlugins } from '../pageobjects/dashboard/workspace-details/WorkspaceDetailsPlugins'; import { ScreenCatcher } from '../utils/ScreenCatcher'; import { OcpLoginPage } from '../pageobjects/openshift/OcpLoginPage'; import { CheLoginPage } from '../pageobjects/openshift/CheLoginPage'; import { IAuthorizationHeaderHandler } from '../utils/request-handlers/headers/IAuthorizationHeaderHandler'; import { CheMultiuserAuthorizationHeaderHandler } from '../utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler'; -import { CheMultiuserTokenHandler } from '../utils/request-handlers/tokens/CheMultiuserTokenHandler'; -import { ITokenHandler } from '../utils/request-handlers/tokens/ITokenHandler'; import { CheApiRequestHandler } from '../utils/request-handlers/CheApiRequestHandler'; -import { CheGitApi } from '../utils/vsc/CheGitApi'; -import { GitHubUtil } from '../utils/vsc/github/GitHubUtil'; import { CreateWorkspace } from '../pageobjects/dashboard/CreateWorkspace'; import { UpdateAccountInformationPage } from '../pageobjects/login/UpdateAccountInformationPage'; import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; import { WorkspaceHandlingTests } from '../tests-library/WorkspaceHandlingTests'; -import { GitLoginPage } from '../pageobjects/third-parties/GitLoginPage'; -import { GitOauthAppsSettings } from '../pageobjects/third-parties/GitOauthAppsSettings'; -import { WorkspaceNameHandler } from '../utils/WorkspaceNameHandler'; import { Sanitizer } from '../utils/Sanitizer'; import { ApiUrlResolver } from '../utils/workspace/ApiUrlResolver'; import { ITestWorkspaceUtil } from '../utils/workspace/ITestWorkspaceUtil'; import { ProjectAndFileTests } from '../tests-library/ProjectAndFileTests'; import { LoginTests } from '../tests-library/LoginTests'; +import { RedHatLoginPage } from '../pageobjects/login/RedHatLoginPage'; +import { OcpRedHatLoginPage } from '../pageobjects/login/OcpRedHatLoginPage'; const e2eContainer: Container = new Container({ defaultScope: 'Transient' }); @@ -54,7 +48,6 @@ e2eContainer.bind(TYPES.Driver).to(ChromeDriver).inSingletonScope(); e2eContainer.bind(TYPES.WorkspaceUtil).to(TestWorkspaceUtil); e2eContainer.bind(TYPES.OcpLogin).to(OcpUserLoginPage); e2eContainer.bind(TYPES.IAuthorizationHeaderHandler).to(CheMultiuserAuthorizationHeaderHandler); -e2eContainer.bind(TYPES.ITokenHandler).to(CheMultiuserTokenHandler); if (JSON.parse(TestConstants.TS_SELENIUM_VALUE_OPENSHIFT_OAUTH)) { e2eContainer.bind(TYPES.CheLogin).to(RegularUserOcpCheLoginPage); @@ -67,22 +60,21 @@ e2eContainer.bind(CLASSES.DriverHelper).to(DriverHelper); e2eContainer.bind(CLASSES.Dashboard).to(Dashboard); e2eContainer.bind(CLASSES.Workspaces).to(Workspaces); e2eContainer.bind(CLASSES.WorkspaceDetails).to(WorkspaceDetails); -e2eContainer.bind(CLASSES.WorkspaceDetailsPlugins).to(WorkspaceDetailsPlugins); e2eContainer.bind(CLASSES.ScreenCatcher).to(ScreenCatcher); e2eContainer.bind(CLASSES.OcpLoginPage).to(OcpLoginPage); e2eContainer.bind(CLASSES.CheLoginPage).to(CheLoginPage); e2eContainer.bind(CLASSES.CheApiRequestHandler).to(CheApiRequestHandler); -e2eContainer.bind(CLASSES.CheGitApi).to(CheGitApi); -e2eContainer.bind(CLASSES.GitHubUtil).to(GitHubUtil); e2eContainer.bind(CLASSES.CreateWorkspace).to(CreateWorkspace); e2eContainer.bind(CLASSES.UpdateAccountInformationPage).to(UpdateAccountInformationPage); e2eContainer.bind(CLASSES.ProjectAndFileTests).to(ProjectAndFileTests); e2eContainer.bind(CLASSES.LoginTests).to(LoginTests); -e2eContainer.bind(CLASSES.WorkspaceNameHandler).to(WorkspaceNameHandler); -e2eContainer.bind(CLASSES.GitLoginPage).to(GitLoginPage); -e2eContainer.bind(CLASSES.GitOauthAppsSettings).to(GitOauthAppsSettings); e2eContainer.bind(CLASSES.Sanitizer).to(Sanitizer); e2eContainer.bind(CLASSES.ApiUrlResolver).to(ApiUrlResolver); e2eContainer.bind(CLASSES.WorkspaceHandlingTests).to(WorkspaceHandlingTests); +if (TestConstants.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE === 'DevSandbox') { + e2eContainer.bind(CLASSES.RedHatLoginPage).to(RedHatLoginPage); + e2eContainer.rebind(TYPES.CheLogin).to(OcpRedHatLoginPage); +} + export { e2eContainer }; diff --git a/tests/e2e/configs/inversify.types.ts b/tests/e2e/configs/inversify.types.ts index e3d78f6ae3f2..3fedd4a34e82 100644 --- a/tests/e2e/configs/inversify.types.ts +++ b/tests/e2e/configs/inversify.types.ts @@ -22,50 +22,21 @@ const CLASSES = { DriverHelper: 'DriverHelper', Dashboard: 'Dashboard', Workspaces: 'Workspaces', - NewWorkspace: 'NewWorkspace', WorkspaceDetails: 'WorkspaceDetails', - WorkspaceDetailsPlugins: 'WorkspaceDetailsPlugins', - Ide: 'Ide', - ProjectTree: 'ProjectTree', - OpenEditors: 'OpenEditors', - Editor: 'Editor', - TopMenu: 'TopMenu', - QuickOpenContainer: 'QuickOpenContainer', - PreviewWidget: 'PreviewWidget', - GitHubPlugin: 'GitHubPlugin', - RightToolBar: 'RightToolBar', - LeftToolBar: 'LeftToolBar', - Terminal: 'Terminal', - DebugView: 'DebugView', - DialogWindow: 'DialogWindow', ScreenCatcher: 'ScreenCatcher', - OpenshiftPlugin: 'OpenshiftPlugin', OcpLoginPage: 'OcpLoginPage', - OpenWorkspaceWidget: 'OpenWorkspaceWidget', - ContextMenu: 'ContextMenu', CheLoginPage: 'CheLoginPage', - GitHubUtil: 'GitHubUtil', - CheGitApi: 'CheGitApi', - GitPlugin: 'GitPlugin', - NotificationCenter: 'NotificationCenter', CheApiRequestHandler: 'CheApiRequestHandler', CreateWorkspace: 'CreateWorkspace', - OpenDialogWidget: 'OpenDialogWidget', UpdateAccountInformationPage: 'UpdateAccountInformationPage', - KubernetesPlugin: 'KubernetesPlugin', BrowserTabsUtil: 'BrowserTabsUtil', - PluginsView: 'PluginsView', ProjectAndFileTests: 'ProjectAndFileTests', - WorkspaceNameHandler: 'WorkspaceNameHandler', - GitHubPullRequestPlugin: 'GitHubPullRequestPlugin', - GitLoginPage: 'GitLoginPage', - GitOauthAppsSettings: 'GitOauthAppsSettings', - AnimationChecker: 'AnimationChecker', Sanitizer: 'Sanitizer', - NavigationBar: 'NavigationBar', ApiUrlResolver: 'ApiUrlResolver', LoginTests: 'LoginTests', - WorkspaceHandlingTests: 'WorkspaceHandlingTests' + WorkspaceHandlingTests: 'WorkspaceHandlingTests', + RedHatLoginPage: 'RedHatLoginPage', + OcpRedHatLoginPage: 'OcpRedHatLoginPage', }; export { TYPES, CLASSES }; diff --git a/tests/e2e/configs/mocharc.ts b/tests/e2e/configs/mocharc.ts index 22e9e1b5a67f..2cb8e03fb11f 100644 --- a/tests/e2e/configs/mocharc.ts +++ b/tests/e2e/configs/mocharc.ts @@ -15,7 +15,9 @@ module.exports = { process.env.USERSTORY ? `dist/specs/${process.env.MOCHA_DIRECTORY}/${process.env.USERSTORY}.spec.js` : `dist/specs/${process.env.MOCHA_DIRECTORY}/**.spec.js` - : `dist/specs/**/**.spec.js`, + : process.env.USERSTORY ? + `dist/specs/**/${process.env.USERSTORY}.spec.js` + : `dist/specs/**/**.spec.js`, grep: process.env.MOCHA_SUITE ? process.env.MOCHA_SUITE : '', retries: process.env.MOCHA_RETRIES ? process.env.MOCHA_RETRIES : 3, }; diff --git a/tests/e2e/constants/TestConstants.ts b/tests/e2e/constants/TestConstants.ts index 6c2adbc4cf51..1e474076a0e0 100644 --- a/tests/e2e/constants/TestConstants.ts +++ b/tests/e2e/constants/TestConstants.ts @@ -17,6 +17,12 @@ function getBaseUrl(): string { return baseUrl.replace(/\/$/, ''); } +export enum GitProviderType { + GITHUB = 'github', + GITLAB = 'gitlab', + BITBUCKET = 'bitbucket' +} + export enum EditorType { THEIA = 'theia', CHE_CODE = 'che-code' @@ -98,14 +104,14 @@ export const TestConstants = { TS_SELENIUM_WORKSPACE_STATUS_POLLING: Number(process.env.TS_SELENIUM_WORKSPACE_STATUS_POLLING) || 10000, /** - * Amount of tries for checking plugin precence. + * Amount of tries for checking plugin presence. */ - TS_SELENIUM_PLUGIN_PRECENCE_ATTEMPTS: Number(process.env.TS_SELENIUM_PLUGIN_PRECENCE_ATTEMPTS) || 20, + TS_SELENIUM_PLUGIN_PRESENCE_ATTEMPTS: Number(process.env.TS_SELENIUM_PLUGIN_PRECENCE_ATTEMPTS) || 20, /** * Name of workspace created for 'Happy Path' scenario validation. */ - TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME: process.env.TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME || 'petclinic-dev-environment', + TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME: process.env.TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME || 'EmptyWorkspace', /** * Using 'single-host' strategy, "false" by default. @@ -211,86 +217,79 @@ export const TestConstants = { /** * Running test suite - possible variants can be found in package.json scripts part. */ - TEST_SUITE: process.env.TEST_SUITE || 'test-happy-path', + TEST_SUITE: process.env.TEST_SUITE || 'userstory', /** - * The repo (with README.md in root) and access token are needed for to run test-git-ssh + * Print all timeout variables when tests launch, defaulte to false */ - TS_GITHUB_TEST_REPO: process.env.TS_GITHUB_TEST_REPO || '', + TS_SELENIUM_PRINT_TIMEOUT_VARIABLES: process.env.TS_SELENIUM_PRINT_TIMEOUT_VARIABLES || false, /** - * Token for a github repository with permissions which allow add the ssh keys + * URL of the workspace created by devworkspace-controller */ - TS_GITHUB_TEST_REPO_ACCESS_TOKEN: process.env.TS_GITHUB_TEST_REPO_ACCESS_TOKEN || '', + TS_SELENIUM_DEVWORKSPACE_URL: process.env.TS_SELENIUM_DEVWORKSPACE_URL, /** - * Username of the github account + * This variable specifies that run test is used for load testing and that all artifacts will be sent to ftp client. */ - TS_GITHUB_USERNAME: process.env.TS_GITHUB_USERNAME || '', + TS_LOAD_TESTS: process.env.TS_LOAD_TESTS || 'false', /** - * Password of the github account + * Constant, which prolong timeout constants for local debug. */ - TS_GITHUB_PASSWORD: process.env.TS_GITHUB_PASSWORD || '', + TS_DEBUG_MODE: process.env.TS_DEBUG_MODE === 'true', /** - * Login for a user whom has been created in the test Openshift cluster. Need for Openshift connector test + * Path to the folder with upstream "Che" */ - TS_TEST_OPENSHIFT_PLUGIN_USERNAME: process.env.TS_TEST_OPENSHIFT_PLUGIN_USERNAME || '', + E2E_PATH_TO_UPSTREAM_PACKAGE: process.env.E2E_PATH_TO_UPSTREAM || '/tmp/che/tests/e2e', - /** - * Password for a user whom has been created in the test Openshift cluster. Need for Openshift connector test - */ - TS_TEST_OPENSHIFT_PLUGIN_PASSWORD: process.env.TS_TEST_OPENSHIFT_PLUGIN_PASSWORD || '', + E2E_OCP_CLUSTER_VERSION: process.env.E2E_OCP_CLUSTER_VERSION || '4.x', - /** - * The name of project in the Openshift plugin tree - */ - TS_TEST_OPENSHIFT_PLUGIN_PROJECT: process.env.TS_TEST_OPENSHIFT_PLUGIN_PROJECT || '', + E2E_OCP_CLUSTER_API_URL: process.env.E2E_OCP_CLUSTER_API_URL || '', - /** - * The name of the Openshift connector plugin component type - */ - TS_TEST_OPENSHIFT_PLUGIN_COMPONENT_TYPE: process.env.TS_TEST_OPENSHIFT_PLUGIN_COMPONENT_TYPE || 'nodejs (s2i)', + E2E_OPENSHIFT_TOKEN: process.env.E2E_OPENSHIFT_TOKEN || '', + E2E_ANOTHER_WINDOW_TIMEOUT: Number(process.env.E2E_ANOTHER_WINDOW_TIMEOUT) || 60000, - /** - * The name of the Openshift connector plugin component version - */ - TS_TEST_OPENSHIFT_PLUGIN_COMPONENT_VERSION: process.env.TS_TEST_OPENSHIFT_PLUGIN_COMPONENT_VERSION || 'latest', + TS_SELENIUM_VALUE_TLS_SUPPORT: process.env.TS_SELENIUM_VALUE_TLS_SUPPORT || 'true', /** - * Print all timeout variables when tests launch, defaulte to false + * Timeout for dialog window, "120 000" by default */ - TS_SELENIUM_PRINT_TIMEOUT_VARIABLES: process.env.TS_SELENIUM_PRINT_TIMEOUT_VARIABLES || false, + TS_DIALOG_WINDOW_TIMEOUT: Number(process.env.TS_DIALOG_WINDOW_TIMEOUT) || 120_000, - /** - * URL of the workspace created by devworkspace-controller - */ - TS_SELENIUM_DEVWORKSPACE_URL: process.env.TS_SELENIUM_DEVWORKSPACE_URL, + /* ------------------------------------------- + | The factory tests related constants + ----------------------------------------------*/ + TS_SELENIUM_FACTORY_GIT_PROVIDER: process.env.TS_SELENIUM_FACTORY_GIT_PROVIDER || GitProviderType.GITHUB, - /** - * This variable specifies that run test is used for load testing and that all artifacts will be sent to ftp client. - */ - TS_LOAD_TESTS: process.env.TS_LOAD_TESTS || 'false', + TS_SELENIUM_FACTORY_GIT_REPO_URL: process.env.TS_SELENIUM_FACTORY_GIT_REPO_URL || '', - /** - * This variable determines whether to delete the workspace after the test or leave the workspace running. - */ - TS_DELETE_PLUGINS_TEST_WORKSPACE: process.env.TS_DELETE_PLUGINS_TEST_WORKSPACE || 'true', + TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO: true, - /** - * URL of Gogs self-hosted Git server. - */ - TS_SELF_HOSTED_GIT_SERVER_URL: process.env.TS_SELF_HOSTED_GIT_SERVER_URL || '10.0.104.86:10080', + TS_SELENIUM_FACTORY_GIT_REPO_BRANCH: process.env.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH || 'master', - /** - * URL of workspace devfile test repository. - */ - TS_TEST_WORKSPACE_DEVFILE_REPO: process.env.TS_TEST_WORKSPACE_DEVFILE_REPO || '', + TS_SELENIUM_FACTORY_URL() { + return process.env.TS_SELENIUM_FACTORY_URL || TestConstants.TS_SELENIUM_BASE_URL + '/dashboard/#/' + this.TS_SELENIUM_FACTORY_GIT_REPO_URL; + }, - /** - * Constant, which prolong timeout constants for local debug. - */ - TS_DEBUG_MODE: process.env.TS_DEBUG_MODE || false + TS_SELENIUM_GIT_PROVIDER_USERNAME: process.env.TS_SELENIUM_GIT_PROVIDER_USERNAME || '', + + TS_SELENIUM_GIT_PROVIDER_PASSWORD: process.env.TS_SELENIUM_GIT_PROVIDER_PASSWORD || '', + + TS_SELENIUM_GIT_PROVIDER_IS_LDAP_LOGIN: process.env.TS_SELENIUM_GIT_PROVIDER_IS_LDAP_LOGIN || false, + + TS_SELENIUM_GIT_PROVIDER_OAUTH: process.env.TS_SELENIUM_GIT_PROVIDER_OAUTH || false, + + TS_SELENIUM_PROJECT_ROOT_FILE_NAME: process.env.TS_SELENIUM_PROJECT_ROOT_FILE_NAME || 'devfile.yaml', + + /* ------------------------------------------- + | The airgap mode related constants + ----------------------------------------------*/ + TS_SELENIUM_TYPESCRIPT_DEBUG_IMAGE: process.env.TS_SELENIUM_TYPESCRIPT_DEBUG_IMAGE || 'quay.io/eclipse/che-nodejs10-ubi:7.35.2', + + TS_SELENIUM_PHP_DEBUG_IMAGE: process.env.TS_SELENIUM_PHP_DEBUG_IMAGE || 'registry.redhat.io/codeready-workspaces/stacks-php-rhel8:latest', + + TS_SELENIUM_PROJECT_TYPE: process.env.TS_SELENIUM_PROJECT_TYPE || 'zip' }; diff --git a/tests/e2e/files/devfiles/plugins/GitHubPullRequestPlugin.yaml b/tests/e2e/files/devfiles/plugins/GitHubPullRequestPlugin.yaml deleted file mode 100644 index 705a71434d87..000000000000 --- a/tests/e2e/files/devfiles/plugins/GitHubPullRequestPlugin.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: github-pr-plugin -projects: - - name: Spoon-Knife - source: - location: 'https://github.com/chepullreq4/Spoon-Knife.git' - type: git -components: - - id: ms-vscode/vscode-github-pullrequest/latest - type: chePlugin diff --git a/tests/e2e/files/devfiles/plugins/InstallPluginUsingUI.yaml b/tests/e2e/files/devfiles/plugins/InstallPluginUsingUI.yaml deleted file mode 100644 index 36015410b175..000000000000 --- a/tests/e2e/files/devfiles/plugins/InstallPluginUsingUI.yaml +++ /dev/null @@ -1,3 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: install-plugin-test diff --git a/tests/e2e/files/devfiles/plugins/Java11PluginTest.yaml b/tests/e2e/files/devfiles/plugins/Java11PluginTest.yaml deleted file mode 100644 index 91f0c8848549..000000000000 --- a/tests/e2e/files/devfiles/plugins/Java11PluginTest.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: java11-plugin-test -projects: - - name: console-java-simple - source: - location: 'https://github.com/che-samples/console-java-simple.git' - type: git - branch: java1.11 -components: - - type: cheEditor - id: eclipse/che-theia/next - memoryLimit: 512Mi - - id: redhat/java/latest - preferences: - java.server.launchMode: Standard - type: chePlugin diff --git a/tests/e2e/files/devfiles/plugins/PhpPluginTest.yaml b/tests/e2e/files/devfiles/plugins/PhpPluginTest.yaml deleted file mode 100644 index b7e1ea56234a..000000000000 --- a/tests/e2e/files/devfiles/plugins/PhpPluginTest.yaml +++ /dev/null @@ -1,47 +0,0 @@ ---- -apiVersion: 1.0.0 -metadata: - generateName: php-plugin-test -projects: -- name: php-web-simple - source: - type: git - location: "https://github.com/che-samples/web-php-simple" -components: -- type: chePlugin - id: bmewburn/vscode-intelephense-client/latest -- type: chePlugin - id: felixfbecker/php-debug/latest -- type: dockerimage - alias: php - image: quay.io/eclipse/che-php-7:next - memoryLimit: 512Mi - mountSources: true - endpoints: - - name: '8080-tcp' - port: 8080 - volumes: - - name: composer - containerPath: "/home/user/.composer" - - name: symfony - containerPath: "/home/user/.symfony" -commands: -- name: Debug current file - actions: - - type: vscode-launch - referenceContent: | - { - "version": "0.2.0", - "configurations": [ - { - "name": "Launch currently open script", - "type": "php", - "request": "launch", - "program": "${file}", - "stopOnEntry": true, - "cwd": "${fileDirname}", - "port": 9000, - "runtimeExecutable": "php" - } - ] - } diff --git a/tests/e2e/files/devfiles/plugins/PythonPluginTest.yaml b/tests/e2e/files/devfiles/plugins/PythonPluginTest.yaml deleted file mode 100644 index 9b4ee17469f5..000000000000 --- a/tests/e2e/files/devfiles/plugins/PythonPluginTest.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: python-plugin-test -projects: - - name: python-hello-world - source: - location: 'https://github.com/che-samples/python-hello-world.git' - type: git -components: - - id: ms-python/python/latest - type: chePlugin - - type: cheEditor - id: eclipse/che-theia/next - memoryLimit: 512Mi diff --git a/tests/e2e/files/devfiles/plugins/TypescriptNodeDebug2PluginTest.yaml b/tests/e2e/files/devfiles/plugins/TypescriptNodeDebug2PluginTest.yaml deleted file mode 100644 index 78d8e8f65cb4..000000000000 --- a/tests/e2e/files/devfiles/plugins/TypescriptNodeDebug2PluginTest.yaml +++ /dev/null @@ -1,49 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: typescript-debug-plugins -projects: - - name: nodejs-web-app - source: - location: 'https://github.com/che-samples/web-nodejs-sample.git' - branch: che-qe-tests - type: git -components: - - id: vscode/typescript-language-features/latest - type: chePlugin - - id: ms-vscode/node-debug2/latest - preferences: - debug.node.useV3: false - type: chePlugin - - mountSources: true - endpoints: - - name: nodejs - port: 3000 - memoryLimit: 512Mi - type: dockerimage - alias: nodejs - image: 'quay.io/eclipse/che-nodejs10-ubi:next' -commands: - - name: run the web app (debugging enabled) - actions: - - workdir: '${CHE_PROJECTS_ROOT}/nodejs-web-app/app' - type: exec - command: npm install && nodemon --inspect app.js - component: nodejs - - name: Attach remote debugger - actions: - - referenceContent: | - { - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "attach", - "name": "Attach to Remote", - "address": "localhost", - "port": 9229, - "localRoot": "${workspaceFolder}", - "remoteRoot": "${workspaceFolder}" - } - ] - } - type: vscode-launch diff --git a/tests/e2e/files/devfiles/plugins/VscodeKubernetesPlugin.yaml b/tests/e2e/files/devfiles/plugins/VscodeKubernetesPlugin.yaml deleted file mode 100644 index 7a07c661d5e9..000000000000 --- a/tests/e2e/files/devfiles/plugins/VscodeKubernetesPlugin.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: nodejs-24lop -projects: - - name: nodejs-web-app - source: - location: 'https://github.com/che-samples/web-nodejs-sample.git' - branch: che-qe-tests - type: git -components: - - type: chePlugin - id: ms-kubernetes-tools/vscode-kubernetes-tools/latest diff --git a/tests/e2e/files/devfiles/plugins/VscodeShellcheckPlugin.yaml b/tests/e2e/files/devfiles/plugins/VscodeShellcheckPlugin.yaml deleted file mode 100644 index 10ec5687d538..000000000000 --- a/tests/e2e/files/devfiles/plugins/VscodeShellcheckPlugin.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: nodejs-zmecm -projects: - - name: nodejs-web-app - source: - location: 'https://github.com/che-samples/web-nodejs-sample.git' - branch: che-qe-tests - type: git -components: - - id: timonwong/shellcheck/latest - type: chePlugin diff --git a/tests/e2e/files/devfiles/plugins/VscodeValePlugin.yaml b/tests/e2e/files/devfiles/plugins/VscodeValePlugin.yaml deleted file mode 100644 index e3a71a442876..000000000000 --- a/tests/e2e/files/devfiles/plugins/VscodeValePlugin.yaml +++ /dev/null @@ -1,42 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: che-docs-test -projects: - - name: che-docs - source: - location: 'https://github.com/eclipse/che-docs.git' - type: git - branch: che-qe -components: - - mountSources: true - endpoints: - - name: Open-Livereload - port: 35729 - - attributes: - path: /che-7/overview/introduction-to-eclipse-che/ - name: Open-Preview-server - port: 4000 - command: - - tail - args: - - '-f' - - /dev/null - memoryLimit: 512M - type: dockerimage - alias: che-docs - image: 'quay.io/eclipse/che-docs:latest' - - preferences: - vale.core.useCLI: true - type: chePlugin - reference: 'https://che-plugin-registry-main.surge.sh/v3/plugins/errata-ai/vale-server/latest/meta.yaml' - alias: vale-server - - id: redhat/vscode-yaml/latest - type: chePlugin - - id: redhat/vscode-xml/latest - type: chePlugin - - id: redhat/java/latest - type: chePlugin - - id: golang/go/latest - type: chePlugin - - id: vscode/typescript-language-features/latest - type: chePlugin diff --git a/tests/e2e/files/devfiles/plugins/VscodeXmlPlugin.yaml b/tests/e2e/files/devfiles/plugins/VscodeXmlPlugin.yaml deleted file mode 100644 index 942642ac1a85..000000000000 --- a/tests/e2e/files/devfiles/plugins/VscodeXmlPlugin.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: xml-plugin-test -projects: - - name: nodejs-web-app - source: - location: 'https://github.com/che-samples/web-nodejs-sample.git' - branch: che-qe-tests - type: git -components: - - id: redhat/vscode-xml/latest - type: chePlugin diff --git a/tests/e2e/files/devfiles/plugins/VscodeYamlPlugin.yaml b/tests/e2e/files/devfiles/plugins/VscodeYamlPlugin.yaml deleted file mode 100644 index e11d7ed3b7ec..000000000000 --- a/tests/e2e/files/devfiles/plugins/VscodeYamlPlugin.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: 1.0.0 -metadata: - name: nodejs-zmecm -projects: - - name: nodejs-web-app - source: - location: 'https://github.com/che-samples/web-nodejs-sample.git' - branch: che-qe-tests - type: git -components: - - id: redhat/vscode-yaml/latest - type: chePlugin diff --git a/tests/e2e/files/happy-path/containers-happy-path.yaml b/tests/e2e/files/happy-path/containers-happy-path.yaml deleted file mode 100644 index 6203ab6535d8..000000000000 --- a/tests/e2e/files/happy-path/containers-happy-path.yaml +++ /dev/null @@ -1,127 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: mysql - labels: - app.kubernetes.io/name: mysql - app.kubernetes.io/component: database - app.kubernetes.io/part-of: petclinic -spec: - ports: - - port: 3306 - targetPort: 3306 - selector: - app.kubernetes.io/name: mysql - app.kubernetes.io/component: database - app.kubernetes.io/part-of: petclinic ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: db - labels: - app.kubernetes.io/name: mysql - app.kubernetes.io/component: database - app.kubernetes.io/part-of: petclinic -spec: - selector: - matchLabels: - app.kubernetes.io/name: mysql - app.kubernetes.io/component: database - app.kubernetes.io/part-of: petclinic - replicas: 1 - template: - metadata: - labels: - app.kubernetes.io/name: mysql - app.kubernetes.io/component: database - app.kubernetes.io/part-of: petclinic - spec: - containers: - - name: mysql - image: quay.io/eclipse/che--centos--mysql-57-centos7:latest-e08ee4d43b7356607685b69bde6335e27cf20c020f345b6c6c59400183882764 - resources: - requests: - memory: 256Mi - env: - - name: MYSQL_USER - value: petclinic - - name: MYSQL_PASSWORD - value: petclinic - - name: MYSQL_ROOT_PASSWORD - value: petclinic - - name: MYSQL_DATABASE - value: petclinic - ports: - - containerPort: 3306 ---- -apiVersion: v1 -kind: Service -metadata: - name: spring-boot-app - labels: - app.kubernetes.io/name: petclinic - app.kubernetes.io/component: webapp - app.kubernetes.io/part-of: petclinic -spec: - ports: - - port: 8080 - targetPort: 8080 - selector: - app.kubernetes.io/name: petclinic - app.kubernetes.io/component: webapp - app.kubernetes.io/part-of: petclinic ---- -apiVersion: apps/v1 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1 -kind: Deployment -metadata: - name: spring-boot-app - labels: - app.kubernetes.io/name: petclinic - app.kubernetes.io/component: webapp - app.kubernetes.io/part-of: petclinic -spec: - selector: - matchLabels: - app.kubernetes.io/name: petclinic - app.kubernetes.io/component: webapp - app.kubernetes.io/part-of: petclinic - replicas: 1 - template: - metadata: - labels: - app.kubernetes.io/name: petclinic - app.kubernetes.io/component: webapp - app.kubernetes.io/part-of: petclinic - spec: - containers: - - name: spring-boot - image: quay.io/mloriedo/spring-petclinic - resources: - requests: - memory: 512Mi - ports: - - containerPort: 8080 ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: spring-boot-app - labels: - app: spring-petclinic - tier: frontend - annotations: - kubernetes.io/ingress.class: "nginx" - nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" - nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600" - nginx.ingress.kubernetes.io/ssl-redirect: "false" -spec: - rules: - - host: 192.168.99.100.nip.io - http: - paths: - - path: / - backend: - serviceName: spring-boot-app - servicePort: 8080 diff --git a/tests/e2e/files/happy-path/happy-path-workspace.yaml b/tests/e2e/files/happy-path/happy-path-workspace.yaml deleted file mode 100644 index c72daf0996bd..000000000000 --- a/tests/e2e/files/happy-path/happy-path-workspace.yaml +++ /dev/null @@ -1,95 +0,0 @@ ---- -apiVersion: 1.0.0 -metadata: - name: petclinic-dev-environment -projects: - - name: petclinic - source: - type: git - location: "https://github.com/spring-projects/spring-petclinic.git" - commitId: e7c879ed3abe10e446ff103887ad665ca6acf04e -components: - - type: cheEditor - id: eclipse/che-theia/next - memoryLimit: 512Mi - - type: kubernetes - alias: petclinic-web - reference: https://raw.githubusercontent.com/eclipse/che/master/tests/e2e/files/happy-path/containers-happy-path.yaml - selector: - app.kubernetes.io/component: webapp - entrypoints: - - containerName: spring-boot - command: ["tail"] - args: ["-f", "/dev/null"] - - type: kubernetes - alias: petclinic-db - reference: https://raw.githubusercontent.com/eclipse/che/master/tests/e2e/files/happy-path/containers-happy-path.yaml - selector: - app.kubernetes.io/component: database - - type: dockerimage - alias: maven-container - image: quay.io/eclipse/happy-path:next - env: - - name: MAVEN_CONFIG - value: /home/user/.m2 - memoryLimit: 1500Mi - endpoints: - - name: '8080-tcp' - port: 8080 - - name: 'debug' - port: 5005 - attributes: - public: 'false' - mountSources: true - - type: chePlugin - id: redhat/java/latest - memoryLimit: "1000Mi" - preferences: - java.server.launchMode: Standard - - type: chePlugin - id: redhat/vscode-yaml/latest -commands: - - name: build - actions: - - type: exec - component: maven-container - command: mvn clean package | tee /workspace_logs/build.log && tail -n 40 /workspace_logs/build.log | grep 'BUILD SUCCESS' > /projects/petclinic/result-build.txt - workdir: /projects/petclinic - - name: build-file-output - actions: - - type: exec - component: maven-container - command: cd /projects/petclinic && mvn package | tee /workspace_logs/build-output.log && tail -n 40 /workspace_logs/build-output.log | grep 'BUILD SUCCESS' > /projects/petclinic/result-build-output.txt - - name: run - actions: - - type: exec - component: maven-container - command: java -jar spring-petclinic-2.4.5.jar --spring.profiles.active=mysql | tee /workspace_logs/run.log - workdir: /projects/petclinic/target - - name: run-with-changes - actions: - - type: exec - component: maven-container - command: java -jar spring-petclinic-2.4.5.jar --spring.profiles.active=mysql | tee /workspace_logs/run-with-changes.log - workdir: /projects/petclinic/target - - name: run-debug - actions: - - type: exec - component: maven-container - command: java -jar -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 spring-petclinic-2.4.5.jar --spring.profiles.active=mysql | tee /workspace_logs/run-debug.log - workdir: /projects/petclinic/target - - name: Debug remote java application - actions: - - type: vscode-launch - referenceContent: | - { - "version": "0.2.0", - "configurations": [ - { - "type": "java", - "name": "Debug (Attach) - Remote", - "request": "attach", - "hostName": "localhost", - "port": 5005 - }] - } diff --git a/tests/e2e/files/happy-path/petclinic-classpath.txt b/tests/e2e/files/happy-path/petclinic-classpath.txt deleted file mode 100644 index 39abf1c5e910..000000000000 --- a/tests/e2e/files/happy-path/petclinic-classpath.txt +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/e2e/index.ts b/tests/e2e/index.ts new file mode 100644 index 000000000000..90d88453c387 --- /dev/null +++ b/tests/e2e/index.ts @@ -0,0 +1,39 @@ +import * as inversifyConfig from './configs/inversify.config'; +export { inversifyConfig }; +export * from './configs/inversify.types'; +export * from './constants/TestConstants'; +export * from './constants/TimeoutConstants'; +export * from './driver/ChromeDriver'; +export * from './driver/IDriver'; +export * from './utils/BrowserTabsUtil'; +export * from './utils/DriverHelper'; +export * from './utils/Logger'; +export * from './utils/request-handlers/CheApiRequestHandler'; +export * from './utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler'; +export * from './utils/request-handlers/headers/IAuthorizationHeaderHandler'; +export * from './utils/Sanitizer'; +export * from './utils/ScreenCatcher'; +export * from './utils/vsc/GitUtil'; +export * from './utils/workspace/ApiUrlResolver'; +export * from './utils/workspace/ITestWorkspaceUtil'; +export * from './utils/workspace/TestWorkspaceUtil'; +export * from './utils/workspace/WorkspaceStatus'; +export * from './pageobjects/dashboard/CreateWorkspace'; +export * from './pageobjects/dashboard/Dashboard'; +export * from './pageobjects/dashboard/workspace-details/WorkspaceDetails'; +export * from './pageobjects/dashboard/Workspaces'; +export * from './pageobjects/git-providers/OauthPage'; +export * from './pageobjects/ide/CheCodeLocatorLoader'; +export * from './pageobjects/login/ICheLoginPage'; +export * from './pageobjects/login/IOcpLoginPage'; +export * from './pageobjects/login/MultiUserLoginPage'; +export * from './pageobjects/login/OcpRedHatLoginPage'; +export * from './pageobjects/login/OcpUserLoginPage'; +export * from './pageobjects/login/RedHatLoginPage'; +export * from './pageobjects/login/RegularUserOcpCheLoginPage'; +export * from './pageobjects/login/UpdateAccountInformationPage'; +export * from './pageobjects/openshift/CheLoginPage'; +export * from './pageobjects/openshift/OcpLoginPage'; +export * from './tests-library/LoginTests'; +export * from './tests-library/ProjectAndFileTests'; +export * from './tests-library/WorkspaceHandlingTests'; diff --git a/tests/e2e/package-lock.json b/tests/e2e/package-lock.json index 47b8e5146fba..1f39b58d0976 100644 --- a/tests/e2e/package-lock.json +++ b/tests/e2e/package-lock.json @@ -10,16 +10,20 @@ "license": "ISC", "dependencies": { "@eclipse-che/api": "latest", + "@types/clone-deep": "^4.0.1", "inversify": "5.0.1", "reflect-metadata": "0.1.13" }, "devDependencies": { + "@types/chai": "^4.3.4", "@types/mocha": "5.2.6", "@types/node": "11.13.4", "@types/rimraf": "2.0.2", "@types/selenium-webdriver": "4.1.3", "axios": "^0.25.0", - "chromedriver": "^109.0.0", + "chai": "^4.3.4", + "chromedriver": "^111.0.0", + "clone-deep": "^4.0.1", "mocha": "^9.1.3", "monaco-page-objects": "3.1.0", "rimraf": "2.6.2", @@ -208,6 +212,17 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "node_modules/@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "node_modules/@types/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-bdkCSkyVHsgl3Goe1y16T9k6JuQx7SiDREkq728QjKmTZkGJZuS8R3gGcnGzVuGBP0mssKrzM/GlMOQxtip9cg==" + }, "node_modules/@types/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", @@ -391,6 +406,15 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -479,6 +503,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -507,6 +549,15 @@ "node": ">=8" } }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -535,9 +586,9 @@ } }, "node_modules/chromedriver": { - "version": "109.0.0", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-109.0.0.tgz", - "integrity": "sha512-jdmBq11IUwfThLFiygGTZ89qbROSQI4bICQjvOVQy2Bqr1LwC+MFkhwyZp3YG99eehQbZuTlQmmfCZBfpewTNA==", + "version": "111.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-111.0.0.tgz", + "integrity": "sha512-XavNYNBBfKIrT8Oi/ywJ0DoOOU+jHF5bQWTkqStFsAXvfCV9VzYN3J+TGAvZdrpXeoixqPRGUxQ2yZhD2iowdQ==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -723,6 +774,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -975,6 +1038,15 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -1392,6 +1464,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -1701,6 +1782,15 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -2273,6 +2363,15 @@ "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/typescript": { "version": "3.9.9", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", @@ -2616,6 +2715,17 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "@types/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-bdkCSkyVHsgl3Goe1y16T9k6JuQx7SiDREkq728QjKmTZkGJZuS8R3gGcnGzVuGBP0mssKrzM/GlMOQxtip9cg==" + }, "@types/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", @@ -2758,6 +2868,12 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2828,6 +2944,21 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2849,6 +2980,12 @@ } } }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -2866,9 +3003,9 @@ } }, "chromedriver": { - "version": "109.0.0", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-109.0.0.tgz", - "integrity": "sha512-jdmBq11IUwfThLFiygGTZ89qbROSQI4bICQjvOVQy2Bqr1LwC+MFkhwyZp3YG99eehQbZuTlQmmfCZBfpewTNA==", + "version": "111.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-111.0.0.tgz", + "integrity": "sha512-XavNYNBBfKIrT8Oi/ywJ0DoOOU+jHF5bQWTkqStFsAXvfCV9VzYN3J+TGAvZdrpXeoixqPRGUxQ2yZhD2iowdQ==", "dev": true, "requires": { "@testim/chrome-version": "^1.1.3", @@ -3019,6 +3156,15 @@ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3195,6 +3341,12 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, "get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -3507,6 +3659,15 @@ "is-unicode-supported": "^0.1.0" } }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -3740,6 +3901,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -4175,6 +4342,12 @@ "tslib": "^1.8.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "typescript": { "version": "3.9.9", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", diff --git a/tests/e2e/package.json b/tests/e2e/package.json index bff1636ba89b..2e668ce31937 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -5,22 +5,28 @@ "main": "dist/index.js", "scripts": { "lint": "tslint --fix -p .", - "tsc": "tsc -p .", + "tsc": "./configs/sh-scripts/generateIndex.sh && tsc -p .", "cleanup-docker": "if [ $(docker ps -a | grep -c selenium-e2e) -gt 0 ]; then docker rm -f $(docker ps --filter \"name=selenium-e2e\" -aq); fi;", "test-docker": "npm run cleanup-docker && docker run -it --shm-size=2g -p 5920:5920 --name selenium-e2e -e TS_SELENIUM_BASE_URL=$TS_SELENIUM_BASE_URL eclipse/che-e2e:nightly", "test-docker-mount-e2e": "npm run cleanup-docker && docker run -it --shm-size=2g -p 5920:5920 --name selenium-e2e -e TS_SELENIUM_BASE_URL=$TS_SELENIUM_BASE_URL -v $(pwd):/tmp/e2e:Z eclipse/che-e2e:nightly", - "test-all-devfiles": "./configs/sh-scripts/generateIndex.sh && ./configs/sh-scripts/initDefaultValues.sh && ./configs/sh-scripts/initDevfileTests.sh", - "test-regression": "./configs/sh-scripts/generateIndex.sh && ./configs/sh-scripts/initDefaultValues.sh npm run lint && npm run tsc && mocha --config dist/configs/mocharc.js" + "test-all-devfiles": " ./configs/sh-scripts/initDefaultValues.sh && ./configs/sh-scripts/initDevfileTests.sh", + "test-regression": "./configs/sh-scripts/initDefaultValues.sh npm run lint && npm run tsc && mocha --config dist/configs/mocharc.js", + "test-userstory": "./configs/sh-scripts/initDefaultValues.sh npm run lint && npm run tsc && export USERSTORY=$USERSTORY && mocha --config dist/configs/mocharc.js", + "test-suite": "./configs/sh-scripts/initDefaultValues.sh npm run lint && npm run tsc && -e MOCHA_DIRECTORY=$MOCHA_DIRECTORY && mocha --config dist/configs/mocharc.js" }, "author": "Ihor Okhrimenko (iokhrime@redhat.com)", "license": "ISC", "devDependencies": { + "@types/chai": "^4.3.4", + "@types/clone-deep": "^4.0.1", "@types/mocha": "5.2.6", "@types/node": "11.13.4", "@types/rimraf": "2.0.2", "@types/selenium-webdriver": "4.1.3", "axios": "^0.25.0", - "chromedriver": "^109.0.0", + "chai": "^4.3.4", + "chromedriver": "^111.0.0", + "clone-deep": "^4.0.1", "mocha": "^9.1.3", "monaco-page-objects": "3.1.0", "rimraf": "2.6.2", diff --git a/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts b/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts index 9d38cdfda631..642914b55d4c 100644 --- a/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts +++ b/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts @@ -36,14 +36,6 @@ export class CreateWorkspace { await this.waitTitleContains('Create Workspace', timeout); } - async waitSample(sampleName: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`CreateWorkspace.waitSample sampleName: "${sampleName}"`); - - const sampleLocator: By = this.getSampleLocator(sampleName); - - await this.driverHelper.waitVisibility(sampleLocator, timeout); - } - async clickOnSampleNoEditorSelection(sampleName: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { Logger.debug(`CreateWorkspace.clickOnSample sampleName: "${sampleName}"`); diff --git a/tests/e2e/pageobjects/dashboard/Dashboard.ts b/tests/e2e/pageobjects/dashboard/Dashboard.ts index 1acc7a9c6ac3..aa5e062da37d 100644 --- a/tests/e2e/pageobjects/dashboard/Dashboard.ts +++ b/tests/e2e/pageobjects/dashboard/Dashboard.ts @@ -24,6 +24,8 @@ export class Dashboard { private static readonly LOADER_PAGE_STEP_TITLES_XPATH: string = '//*[@data-testid="step-title"]'; private static readonly WORKSPACE_STARTING_PAGE_CSS: string = '.ide-loader-page'; private static readonly LOADER_ALERT_XPATH = '//*[@data-testid="loader-alert"]'; + private static readonly USER_DROPDOWN_MENU_BUTTON_XPATH = `//*[text()="${TestConstants.TS_SELENIUM_OCP_USERNAME}"]//parent::button`; + private static readonly LOGOUT_BUTTON_XPATH = '//button[text()="Logout"]'; constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, @inject(CLASSES.Workspaces) private readonly workspaces: Workspaces) { } @@ -116,9 +118,17 @@ export class Dashboard { } async getRecentWorkspaceName(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT) { - Logger.debug(`Dashboard.recentWorkspaceName`); + Logger.debug(`Dashboard.getRecentWorkspaceName`); return await this.driverHelper.waitAndGetText(By.css('[data-testid="recent-workspace-item"]'), timeout); } + async logout(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT) { + Logger.debug(`Dashboard.logout`); + + await this.openDashboard(); + await this.driverHelper.waitAndClick(By.xpath(Dashboard.USER_DROPDOWN_MENU_BUTTON_XPATH), timeout); + await this.driverHelper.waitAndClick(By.xpath(Dashboard.LOGOUT_BUTTON_XPATH), timeout); + await this.driverHelper.waitDisappearance(By.xpath(Dashboard.USER_DROPDOWN_MENU_BUTTON_XPATH), timeout); + } } diff --git a/tests/e2e/pageobjects/dashboard/Workspaces.ts b/tests/e2e/pageobjects/dashboard/Workspaces.ts index 84e222d28b3c..5a98ab157406 100644 --- a/tests/e2e/pageobjects/dashboard/Workspaces.ts +++ b/tests/e2e/pageobjects/dashboard/Workspaces.ts @@ -88,7 +88,6 @@ export class Workspaces { Logger.debug(`Workspaces.waitActionsPopup of the '${workspaceName}' list item`); await this.driverHelper.waitVisibility(this.getExpandedActionsLocator(workspaceName), timeout); - await this.driverHelper.wait(2000); } async openActionsPopup(workspaceName: string, timeout: number = TimeoutConstants.TS_CONTEXT_MENU_TIMEOUT) { @@ -105,7 +104,7 @@ export class Workspaces { async clickActionsStopWorkspaceButton(workspaceName: string) { Logger.debug(`Workspaces.clickActionsStopWorkspaceButton for the '${workspaceName}' list item`); - // workaround because of issue CRW-3649 + // todo: workaround because of issue CRW-3649 try { await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Stop Workspace')); } catch (e) { @@ -122,7 +121,6 @@ export class Workspaces { const confirmationWindowLocator: By = By.xpath(`//div[@aria-label='Delete workspaces confirmation window']`); await this.driverHelper.waitVisibility(confirmationWindowLocator, timeout); - await this.driverHelper.wait(5000); } diff --git a/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetailsPlugins.ts b/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetailsPlugins.ts deleted file mode 100644 index e8a1e0fc33f8..000000000000 --- a/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetailsPlugins.ts +++ /dev/null @@ -1,95 +0,0 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - **********************************************************************/ -import { DriverHelper } from '../../../utils/DriverHelper'; -import { injectable, inject } from 'inversify'; -import 'reflect-metadata'; -import { CLASSES, TYPES } from '../../../configs/inversify.types'; -import { By } from 'selenium-webdriver'; -import { WorkspaceDetails } from './WorkspaceDetails'; -import { WorkspaceStatus } from '../../../utils/workspace/WorkspaceStatus'; -import { Logger } from '../../../utils/Logger'; -import { TimeoutConstants } from '../../../constants/TimeoutConstants'; -import { ITestWorkspaceUtil } from '../../../utils/workspace/ITestWorkspaceUtil'; - -@injectable() -export class WorkspaceDetailsPlugins { - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, - @inject(CLASSES.WorkspaceDetails) private readonly workspaceDetails: WorkspaceDetails, - @inject(TYPES.WorkspaceUtil) private readonly testWorkspaceUtil: ITestWorkspaceUtil) { } - - async waitPluginListItem(pluginName: string) { - Logger.debug(`WorkspaceDetailsPlugins.waitPluginListItem ${pluginName}`); - - const pluginListItemLocator: By = By.css(this.getPluginListItemCssLocator(pluginName)); - - await this.driverHelper.waitVisibility(pluginListItemLocator, TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT); - } - - async enablePlugin(pluginName: string, pluginVersion?: string) { - Logger.debug(`WorkspaceDetailsPlugins.enablePlugin ${pluginName}:${pluginVersion}`); - - await this.waitPluginDisabling(pluginName, pluginVersion); - await this.clickOnPluginListItemSwitcher(pluginName, pluginVersion); - await this.waitPluginEnabling(pluginName, pluginVersion); - } - - async disablePlugin(pluginName: string, pluginVersion?: string) { - Logger.debug(`WorkspaceDetailsPlugins.disablePlugin ${pluginName}:${pluginVersion}`); - - await this.waitPluginEnabling(pluginName, pluginVersion); - await this.clickOnPluginListItemSwitcher(pluginName, pluginVersion); - await this.waitPluginDisabling(pluginName, pluginVersion); - } - - async addPluginAndOpenWorkspace(namespace: string, workspaceName: string, pluginName: string, pluginId: string, pluginVersion?: string) { - Logger.debug(`WorkspaceDetailsPlugins.addPluginAndOpenWorkspace ${namespace}/${workspaceName} plugin: ${pluginName}:${pluginVersion}`); - - await this.workspaceDetails.selectTab('Plugins'); - await this.enablePlugin(pluginName, pluginVersion); - await this.workspaceDetails.saveChanges(); - await this.workspaceDetails.openWorkspace(namespace, workspaceName); - await this.testWorkspaceUtil.waitWorkspaceStatus(namespace, workspaceName, WorkspaceStatus.RUNNING); - await this.testWorkspaceUtil.waitPluginAdding(namespace, workspaceName, pluginId); - } - - private getPluginListItemCssLocator(pluginName: string, pluginVersion?: string): string { - if (pluginVersion) { - return `.plugin-item div[plugin-item-name*='${pluginName}'][plugin-item-version='${pluginVersion}']`; - } - - return `.plugin-item div[plugin-item-name*='${pluginName}']`; - } - - private getPluginListItemSwitcherCssLocator(pluginName: string, pluginVersion?: string): string { - return `${this.getPluginListItemCssLocator(pluginName, pluginVersion)} md-switch`; - } - - private async clickOnPluginListItemSwitcher(pluginName: string, - pluginVersion?: string, - timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT) { - - const pluginListItemSwitcherLocator = By.css(this.getPluginListItemSwitcherCssLocator(pluginName, pluginVersion)); - - await this.driverHelper.waitAndClick(pluginListItemSwitcherLocator, timeout); - } - - private async waitPluginEnabling(pluginName: string, pluginVersion?: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT) { - const enabledPluginSwitcherLocator: By = By.css(`${this.getPluginListItemCssLocator(pluginName, pluginVersion)} md-switch[aria-checked='true']`); - - await this.driverHelper.waitVisibility(enabledPluginSwitcherLocator, timeout); - } - - private async waitPluginDisabling(pluginName: string, pluginVersion?: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT) { - const disabledPluginSwitcherLocator: By = By.css(`${this.getPluginListItemCssLocator(pluginName, pluginVersion)} md-switch[aria-checked='false']`); - - await this.driverHelper.waitVisibility(disabledPluginSwitcherLocator, timeout); - } - -} diff --git a/tests/e2e/pageobjects/git-providers/OauthPage.ts b/tests/e2e/pageobjects/git-providers/OauthPage.ts new file mode 100644 index 000000000000..b922387ee61f --- /dev/null +++ b/tests/e2e/pageobjects/git-providers/OauthPage.ts @@ -0,0 +1,156 @@ +/********************************************************************* + * Copyright (c) 2019 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 { inject, injectable } from 'inversify'; +import { By } from 'selenium-webdriver'; +import { CLASSES } from '../../configs/inversify.types'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { GitProviderType, TestConstants } from '../../constants/TestConstants'; +import { Logger } from '../../utils/Logger'; +import { TimeoutConstants } from '../../constants/TimeoutConstants'; + +@injectable() +export class OauthPage { + private readonly loginForm: By; + private readonly passwordForm: By; + private readonly submitButton: By; + private readonly approveButton: By; + private readonly denyAccessButton: By; + + constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { + switch (TestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER) { + case GitProviderType.BITBUCKET : { + this.loginForm = By.id('j_username'); + this.passwordForm = By.id('j_password'); + this.approveButton = By.xpath('//*[@id="approve"]'); + this.submitButton = By.xpath('//*[@id="submit"]'); + this.denyAccessButton = By.xpath('//*[@id="deny"]'); + } + break; + case GitProviderType.GITLAB: { + this.loginForm = TestConstants.TS_SELENIUM_GIT_PROVIDER_IS_LDAP_LOGIN ? By.id('username') : By.id('user_login'); + this.passwordForm = TestConstants.TS_SELENIUM_GIT_PROVIDER_IS_LDAP_LOGIN ? By.id('password') : By.id('user_password'); + this.submitButton = TestConstants.TS_SELENIUM_GIT_PROVIDER_IS_LDAP_LOGIN ? By.xpath('//input[@data-qa-selector="sign_in_button"]') : By.xpath('//button[@data-qa-selector="sign_in_button"]'); + this.approveButton = By.xpath('//*[@value="Authorize"]'); + this.denyAccessButton = By.xpath('//input[@value="Deny"]'); + } + break; + case GitProviderType.GITHUB: { + this.loginForm = By.id('login_field'); + this.passwordForm = By.id('password'); + this.approveButton = By.xpath('//*[@id="js-oauth-authorize-btn"]'); + this.submitButton = By.xpath('//*[@value="Sign in"]'); + this.denyAccessButton = By.xpath('//button[contains(., "Cancel")]'); + } + break; + default: { + throw new Error(`Invalid git provider. The value should be ${GitProviderType.GITHUB}, ${GitProviderType.GITLAB} or ${GitProviderType.BITBUCKET}`); + } + } + } + + async waitLoginPage() { + Logger.debug('OauthPage.waitLoginPage'); + + // for gitlab server https://gitlab.cee.redhat.com + if (!TestConstants.TS_SELENIUM_GIT_PROVIDER_IS_LDAP_LOGIN && + TestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.GITLAB) { + { + Logger.debug(`OauthPage.login - go to ${TestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} Standard login section`); + await this.driverHelper.waitAndClick(By.xpath('//a[@data-qa-selector="standard_tab"]')); + } + } + + await this.driverHelper.waitVisibility(this.loginForm, TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM * 3); + } + + async enterUserName(userName: string) { + Logger.debug(`this.enterUserName "${userName}"`); + + await this.driverHelper.enterValue(this.loginForm, userName); + } + + async enterPassword(password: string) { + Logger.debug(`OauthPage.enterPassword`); + + await this.driverHelper.enterValue(this.passwordForm, password); + } + + async clickOnLoginButton() { + Logger.debug('OauthPage.clickOnLoginButton'); + + await this.driverHelper.waitAndClick(this.submitButton); + } + + async waitClosingLoginPage() { + Logger.debug('OauthPage.waitClosingLoginPage'); + + await this.driverHelper.waitDisappearance(this.loginForm); + } + + async waitOauthPage() { + Logger.debug('OauthPage.waitOauthPage'); + + await this.driverHelper.waitVisibility(this.approveButton); + } + + async clickOnApproveButton() { + Logger.debug('OauthPage.clickOnApproveButton'); + + await this.driverHelper.waitAndClick(this.approveButton); + } + + async clickOnDenyAccessButton() { + Logger.debug('OauthPage.clickOnDenyAccessButton'); + + await this.driverHelper.waitAndClick(this.denyAccessButton); + } + + async waitDisappearanceOauthPage() { + Logger.debug('OauthPage.waitDisappearanceOauthPage'); + + await this.driverHelper.waitDisappearance(this.approveButton); + } + + async login() { + Logger.debug('OauthPage.login'); + + await this.waitLoginPage(); + await this.enterUserName(TestConstants.TS_SELENIUM_GIT_PROVIDER_USERNAME); + await this.enterPassword(TestConstants.TS_SELENIUM_GIT_PROVIDER_PASSWORD); + await this.clickOnLoginButton(); + await this.waitClosingLoginPage(); + } + + async confirmAccess() { + Logger.debug('OauthPage.confirmAccess'); + + try { + await this.clickOnApproveButton(); + await this.waitDisappearanceOauthPage(); + } catch (e) { + Logger.debug('OauthPage.confirmAccess - access was not confirmed, retrying to click conformation button'); + // workaround for github oauth conformation page (bot security) + await this.driverHelper.getAction() + .move({ + origin: await this.driverHelper.waitPresence(this.approveButton) + }) + .click() + .perform(); + await this.waitDisappearanceOauthPage(); + } + } + + async denyAccess() { + Logger.debug('OauthPage.denyAccess'); + + await this.clickOnDenyAccessButton(); + await this.waitDisappearanceOauthPage(); + } +} diff --git a/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts b/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts new file mode 100644 index 000000000000..4bbbe4b3b26e --- /dev/null +++ b/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts @@ -0,0 +1,73 @@ +/********************************************************************* + * Copyright (c) 2019 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 { LocatorLoader } from 'monaco-page-objects/out/locators/loader'; +import { getLocatorsPath } from 'vscode-extension-tester-locators'; +import { LocatorDiff, Locators } from 'monaco-page-objects'; +import { By } from 'selenium-webdriver'; +import clone from 'clone-deep'; +import { EditorType, TestConstants } from '../../constants/TestConstants'; +import { Logger } from '../../utils/Logger'; + +/** + * This class allows us to change or add some specific locators base on "monaco-page-object" and "vscode-extension-tester-locators". + * Use method webLocatorDiff(). To change place locator into field "locators", to add - "extras". + * To see full locators list check "node_modules/vscode-extension-tester-locators/out/lib". + */ + +export class CheCodeLocatorLoader extends LocatorLoader { + readonly webCheCodeLocators: Locators; + + constructor() { + super(TestConstants.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, TestConstants.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, getLocatorsPath()); + if (TestConstants.TS_SELENIUM_EDITOR !== EditorType.CHE_CODE) { + Logger.error('Editor is NOT Che-Code. Please, check your test set ups.'); + } + this.webCheCodeLocators = this.mergeLocators() as Locators; + } + + private webLocatorDiff(): LocatorDiff { + return { + locators: { + WelcomeContent: { + text: By.xpath('//*[@class="dialog-message-text" and contains(text(), "trust")]'), + button: By.xpath('//a[contains(., "trust")]') + }, + }, + }; + } + + private merge(target: any, obj: any) { + for (const key in obj) { + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } + + let oldVal: any = obj[key]; + let newVal: any = target[key]; + + if (typeof (newVal) === 'object' && typeof (oldVal) === 'object') { + target[key] = this.merge(newVal, oldVal); + } else { + target[key] = clone(oldVal); + } + } + return target; + } + + private mergeLocators(): Locators { + const target: Locators = super.loadLocators(); + + this.merge(target, this.webLocatorDiff().locators as Locators); + this.merge(target, this.webLocatorDiff().extras as Locators); + + return target; + } +} + diff --git a/tests/e2e/pageobjects/login/OcpRedHatLoginPage.ts b/tests/e2e/pageobjects/login/OcpRedHatLoginPage.ts new file mode 100644 index 000000000000..25128ec19a72 --- /dev/null +++ b/tests/e2e/pageobjects/login/OcpRedHatLoginPage.ts @@ -0,0 +1,49 @@ +/********************************************************************* + * Copyright (c) 2019 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +import { injectable, inject } from 'inversify'; +import { RedHatLoginPage } from './RedHatLoginPage'; +import { CLASSES } from '../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { ICheLoginPage } from './ICheLoginPage'; +import { OcpLoginPage } from '../openshift/OcpLoginPage'; +import { DriverHelper } from '../../utils/DriverHelper'; +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`; + + constructor( + @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage, + @inject(CLASSES.RedHatLoginPage) private readonly redHatLogin: RedHatLoginPage, + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + + async login(): Promise { + Logger.debug('OcpRedHatLoginPage.login'); + + Logger.debug('OcpRedHatLoginPage.login wait for LogInWithOpenShift page and click button'); + await this.driverHelper.waitPresence(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), TimeoutConstants.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.redHatLogin.waitRedHatLoginWelcomePage(); + await this.redHatLogin.enterUserNameRedHat(); + await this.redHatLogin.clickNextButton(); + await this.redHatLogin.enterPasswordRedHat(); + await this.redHatLogin.clickOnLoginButton(); + await this.redHatLogin.waitDisappearanceRedHatLoginWelcomePage(); + } +} diff --git a/tests/e2e/pageobjects/login/RedHatLoginPage.ts b/tests/e2e/pageobjects/login/RedHatLoginPage.ts new file mode 100644 index 000000000000..b60f3fa5924a --- /dev/null +++ b/tests/e2e/pageobjects/login/RedHatLoginPage.ts @@ -0,0 +1,62 @@ +/********************************************************************* + * Copyright (c) 2019 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +import { injectable, inject } from 'inversify'; +import { By } from 'selenium-webdriver'; +import { CLASSES } from '../../configs/inversify.types'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { Logger } from '../../utils/Logger'; +import { TestConstants } from '../../constants/TestConstants'; + +const USERNAME_INPUT_ID: string = 'username-verification'; +const PASSWORD_INPUT_ID: string = 'password'; +const NEXT_BUTTON_ID: string = 'login-show-step2'; +const LOGIN_BUTTON_ID: string = 'rh-password-verification-submit-button'; +const timeout: number = 10000; + +@injectable() +export class RedHatLoginPage { + + constructor( + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + + async waitRedHatLoginWelcomePage() { + Logger.debug('RedHatLoginPage.waitRedHatLoginWelcomePage'); + await this.driverHelper.waitVisibility(By.id(USERNAME_INPUT_ID)); + } + + async enterPasswordRedHat() { + Logger.debug('RedHatLoginPage.enterPasswordRedHat'); + const passwordFieldLocator: By = By.id(PASSWORD_INPUT_ID); + await this.driverHelper.waitVisibility(passwordFieldLocator, 3000); + await this.driverHelper.enterValue(passwordFieldLocator, TestConstants.TS_SELENIUM_PASSWORD, timeout ); + } + async clickOnLoginButton() { + Logger.debug('RedHatLoginPage.clickOnLoginButton'); + const loginButtonLocator: By = By.id(LOGIN_BUTTON_ID); + await this.driverHelper.waitAndClick(loginButtonLocator, timeout); + } + async waitDisappearanceRedHatLoginWelcomePage() { + Logger.debug('RedHatLoginPage.waitDisappearanceRedHatLoginWelcomePage'); + await this.driverHelper.waitDisappearance(By.id(LOGIN_BUTTON_ID)); + } + async enterUserNameRedHat() { + Logger.debug('RedHatLoginPage.enterUserNameRedHat'); + const usernameFieldLocator: By = By.id(USERNAME_INPUT_ID); + await this.driverHelper.waitVisibility(usernameFieldLocator, 20000); + await this.driverHelper.enterValue(usernameFieldLocator, TestConstants.TS_SELENIUM_USERNAME, timeout ); + } + + async clickNextButton() { + Logger.debug('RedHatLoginPage.clickNextButton'); + const nextButtonLocator: By = By.id(NEXT_BUTTON_ID); + await this.driverHelper.waitAndClick(nextButtonLocator, timeout); + } +} diff --git a/tests/e2e/pageobjects/login/RegularUserOcpCheLoginPage.ts b/tests/e2e/pageobjects/login/RegularUserOcpCheLoginPage.ts index 65d384201c99..d94f39cb4f8b 100644 --- a/tests/e2e/pageobjects/login/RegularUserOcpCheLoginPage.ts +++ b/tests/e2e/pageobjects/login/RegularUserOcpCheLoginPage.ts @@ -33,7 +33,7 @@ export class RegularUserOcpCheLoginPage implements ICheLoginPage { async login() { Logger.debug('RegularUserOcpCheLoginPage.login'); - Logger.debug('OcpRedHatLoginPage.login wait for LogInWithOpenShift page and click button'); + Logger.debug('RegularUserOcpCheLoginPage.login wait for LogInWithOpenShift page and click button'); await this.driverHelper.waitPresence(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); @@ -60,13 +60,6 @@ export class RegularUserOcpCheLoginPage implements ICheLoginPage { await this.cheLogin.clickOnSubmitButton(); await this.cheLogin.waitDisappearanceBrokerLoginPage(); } - - if (await this.ocpLogin.isLinkAccountPageVisible()) { - await this.ocpLogin.clickOnLinkAccountButton(); - await this.cheLogin.waitEclipseCheLoginFormPage(); - await this.cheLogin.inputPaswordEclipseCheLoginPage(TestConstants.TS_SELENIUM_PASSWORD); - await this.cheLogin.clickEclipseCheLoginButton(); - } } } diff --git a/tests/e2e/pageobjects/openshift/CheLoginPage.ts b/tests/e2e/pageobjects/openshift/CheLoginPage.ts index c4def281db10..5d1ddd580274 100644 --- a/tests/e2e/pageobjects/openshift/CheLoginPage.ts +++ b/tests/e2e/pageobjects/openshift/CheLoginPage.ts @@ -78,8 +78,8 @@ export class CheLoginPage { async clickOnSubmitButton() { Logger.debug('CheLoginPage.clickOnSubmitButton'); - const submitButtonlocator: By = By.css('input[type=submit]'); - await this.driverHelper.waitAndClick(submitButtonlocator); + const submitButtonLocator: By = By.css('input[type=submit]'); + await this.driverHelper.waitAndClick(submitButtonLocator); } async waitDisappearanceBrokerLoginPage() { diff --git a/tests/e2e/pageobjects/openshift/OcpLoginPage.ts b/tests/e2e/pageobjects/openshift/OcpLoginPage.ts index 0a4a6b4424fe..786fd7645a58 100644 --- a/tests/e2e/pageobjects/openshift/OcpLoginPage.ts +++ b/tests/e2e/pageobjects/openshift/OcpLoginPage.ts @@ -24,12 +24,6 @@ export class OcpLoginPage { constructor( @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } - async openLoginPageOpenShift(url: string) { - Logger.debug('OcpLoginPage.openLoginPageOpenShift'); - - await this.driverHelper.navigateToUrl(url); - } - async waitOpenShiftLoginWelcomePage() { Logger.debug('OcpLoginPage.waitOpenShiftLoginWelcomePage'); @@ -95,19 +89,4 @@ export class OcpLoginPage { await this.driverHelper.waitDisappearance(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH)); } - - async isLinkAccountPageVisible(): Promise { - Logger.debug('OcpLoginPage.isLinkAccountPageVisible'); - - const linkAccountLocator: By = By.id(`linkAccount`); - return await this.driverHelper.waitVisibilityBoolean(linkAccountLocator, 3, 5000); - } - - async clickOnLinkAccountButton() { - Logger.debug('OcpLoginPage.clickOnLinkAccountButton'); - - const linkAccountLocator: By = By.id(`linkAccount`); - this.driverHelper.waitAndClick(linkAccountLocator); - } - } diff --git a/tests/e2e/pageobjects/third-parties/GitLoginPage.ts b/tests/e2e/pageobjects/third-parties/GitLoginPage.ts deleted file mode 100644 index 454a00739a99..000000000000 --- a/tests/e2e/pageobjects/third-parties/GitLoginPage.ts +++ /dev/null @@ -1,81 +0,0 @@ -/********************************************************************* - * Copyright (c) 2021-2023 Red Hat, Inc. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - **********************************************************************/ - -import 'reflect-metadata'; -import { injectable, inject } from 'inversify'; -import { CLASSES } from '../../configs/inversify.types'; -import { DriverHelper } from '../../utils/DriverHelper'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; -import { Logger } from '../../utils/Logger'; -import { By } from 'selenium-webdriver'; -import { TestConstants } from '../../constants/TestConstants'; - -@injectable() -export class GitLoginPage { - private static readonly USERNAME_FIELD_LOCATOR = By.xpath(`//input[@id='login_field']`); - private static readonly PASSWORD_FIELD_LOCATOR = By.xpath(`//input[@id='password']`); - private static readonly SIGN_IN_BUTTON_LOCATOR = By.xpath(`//input[@value='Sign in']`); - - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } - - async login(timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitLoginPage.login'); - - await this.waitPage(timeout); - await this.typeUsername(TestConstants.TS_GITHUB_USERNAME, timeout); - await this.typePassword(TestConstants.TS_GITHUB_PASSWORD, timeout); - await this.clickSignInButton(timeout); - } - - async waitPage(timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitLoginPage.waitPage'); - - await this.waitUsernameField(timeout); - await this.waitPasswordField(timeout); - await this.waitSignInButton(timeout); - } - - async waitUsernameField(timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitLoginPage.waitUsernameField'); - - await this.driverHelper.waitVisibility(GitLoginPage.USERNAME_FIELD_LOCATOR, timeout); - } - - async waitPasswordField(timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitLoginPage.waitPasswordField'); - - await this.driverHelper.waitVisibility(GitLoginPage.PASSWORD_FIELD_LOCATOR, timeout); - } - - async waitSignInButton(timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitLoginPage.waitSignInbutton'); - - await this.driverHelper.waitVisibility(GitLoginPage.SIGN_IN_BUTTON_LOCATOR, timeout); - } - - async typeUsername(username: string, timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitLoginPage.typeUsername'); - - await this.driverHelper.type(GitLoginPage.USERNAME_FIELD_LOCATOR, username, timeout); - } - - async typePassword(password: string, timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitLoginPage.typePassword'); - - await this.driverHelper.type(GitLoginPage.PASSWORD_FIELD_LOCATOR, password, timeout); - } - - async clickSignInButton(timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitLoginPage.clickSignInButton'); - - await this.driverHelper.waitAndClick(GitLoginPage.SIGN_IN_BUTTON_LOCATOR, timeout); - } - -} diff --git a/tests/e2e/pageobjects/third-parties/GitOauthAppsSettings.ts b/tests/e2e/pageobjects/third-parties/GitOauthAppsSettings.ts deleted file mode 100644 index 8ee7d467b7c8..000000000000 --- a/tests/e2e/pageobjects/third-parties/GitOauthAppsSettings.ts +++ /dev/null @@ -1,110 +0,0 @@ -/********************************************************************* - * Copyright (c) 2021-2023 Red Hat, Inc. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - **********************************************************************/ - -import 'reflect-metadata'; -import { injectable, inject } from 'inversify'; -import { CLASSES } from '../../configs/inversify.types'; -import { DriverHelper } from '../../utils/DriverHelper'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; -import { Logger } from '../../utils/Logger'; -import { By, error, Key } from 'selenium-webdriver'; -import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; - -@injectable() -export class GitOauthAppsSettings { - private static readonly GITHUB_OAUTH_APPS_SETTINGS_URL = 'https://github.com/settings/developers'; - private static readonly HOME_PAGE_FIELD_LOCATOR: By = By.xpath(`//input[@id='oauth_application_url']`); - private static readonly CALLBACK_URL_FIELD_LOCATOR: By = By.xpath(`//input[@id='oauth_application_callback_url']`); - private static readonly UPDATE_APPLICATION_BUTTON_LOCATOR: By = By.xpath(`//form[@class='edit_oauth_application']//button[@type='submit']`); - - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, - @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil) { } - - async openPage(timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitOauthAppsSettings.openPage'); - - await this.browserTabsUtil.navigateTo(GitOauthAppsSettings.GITHUB_OAUTH_APPS_SETTINGS_URL); - } - - async waitTitle(title: string, timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitOauthAppsSettings.waitTitle'); - - await this.driverHelper.waitVisibility(this.getTitleLocator(title), timeout); - } - - async waitOauthApp(applicationTitle: string, timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitOauthAppsSettings.waitOauthApp'); - - await this.driverHelper.waitVisibility(this.getOauthAppLocator(applicationTitle), timeout); - } - - async clickOauthApp(applicationTitle: string, timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitOauthAppsSettings.clickOauthApp'); - - await this.driverHelper.waitAndClick(this.getOauthAppLocator(applicationTitle), timeout); - } - - async openOauthApp(title: string, timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitOauthAppsSettings.openOauthApp'); - - await this.driverHelper.waitUntilTrue(async () => { - await this.clickOauthApp(title); - - try { - await this.waitTitle(title, timeout / 3); - return true; - } catch (err) { - if (!(err instanceof error.TimeoutError)) { - throw err; - } - - Logger.debug(`The ${title} oAuth app is not opened, next try.`); - } - - }, timeout); - } - - async scrollToUpdateApplicationButton(timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitOauthAppsSettings.scrollToUpdateApplicationButton'); - - await this.driverHelper.scrollTo(GitOauthAppsSettings.UPDATE_APPLICATION_BUTTON_LOCATOR, timeout); - } - - async typeHomePageUrl(homePageUrl: string, timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitOauthAppsSettings.typeHomePageUrl'); - - await this.driverHelper.type(GitOauthAppsSettings.HOME_PAGE_FIELD_LOCATOR, Key.chord(Key.CONTROL, 'a'), timeout); - await this.driverHelper.type(GitOauthAppsSettings.HOME_PAGE_FIELD_LOCATOR, Key.DELETE, timeout); - await this.driverHelper.type(GitOauthAppsSettings.HOME_PAGE_FIELD_LOCATOR, homePageUrl, timeout); - } - - async typeCallbackUrl(callbackUrl: string, timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitOauthAppsSettings.typeCallbackUrl'); - - await this.driverHelper.type(GitOauthAppsSettings.CALLBACK_URL_FIELD_LOCATOR, Key.chord(Key.CONTROL, 'a'), timeout); - await this.driverHelper.type(GitOauthAppsSettings.CALLBACK_URL_FIELD_LOCATOR, Key.DELETE, timeout); - await this.driverHelper.type(GitOauthAppsSettings.CALLBACK_URL_FIELD_LOCATOR, callbackUrl, timeout); - } - - async clickUpdateApplicationButton(timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - Logger.debug('GitOauthAppsSettings.clickUpdateApplicationButton'); - - await this.driverHelper.waitAndClick(GitOauthAppsSettings.UPDATE_APPLICATION_BUTTON_LOCATOR, timeout); - } - - private getOauthAppLocator(applicationTitle: string, timeout: number = TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT) { - return By.xpath(`//div[@class='TableObject']//a[text()='${applicationTitle}']`); - } - - private getTitleLocator(title: string): By { - return By.xpath(`//main[@id='js-pjax-container']//h2[text()='${title}']`); - } - -} diff --git a/tests/e2e/specs/MochaHooks.ts b/tests/e2e/specs/MochaHooks.ts index 8959a54f01ee..3f939a5534e4 100644 --- a/tests/e2e/specs/MochaHooks.ts +++ b/tests/e2e/specs/MochaHooks.ts @@ -34,7 +34,7 @@ exports.mochaHooks = { beforeAll: [ async function enableRequestInterceptor() { if (TestConstants.TS_SELENIUM_REQUEST_INTERCEPTOR) { - CheApiRequestHandler.enableRequestInteceptor(); + CheApiRequestHandler.enableRequestInterceptor(); } }, async function enableResponseInterceptor() { @@ -47,7 +47,7 @@ exports.mochaHooks = { monacoPageObjects.initPageObjects(TestConstants.TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION, TestConstants.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, vscodeExtensionTesterLocators.getLocatorsPath(), driverHelper.getDriver(), 'google-chrome'); }, async function prolongTimeoutConstantsInDebugMode() { - if (TestConstants.TS_DEBUG_MODE === 'true') { + if (TestConstants.TS_DEBUG_MODE) { for (let [timeout, seconds] of Object.entries(TimeoutConstants)) { Object.defineProperty(TimeoutConstants, timeout, {value: seconds * 100}); } diff --git a/tests/e2e/specs/devfiles/EmptyWorkspace.spec.ts b/tests/e2e/specs/devfiles/EmptyWorkspace.spec.ts index 7218c1e65524..03d48ebf7374 100644 --- a/tests/e2e/specs/devfiles/EmptyWorkspace.spec.ts +++ b/tests/e2e/specs/devfiles/EmptyWorkspace.spec.ts @@ -47,5 +47,6 @@ suite(`${stackName} test`, async () => { test(`Stop and remove workspace`, async () => { await workspaceHandlingTests.stopAndRemoveWorkspace(WorkspaceHandlingTests.getWorkspaceName()); }); + loginTests.logoutFromChe(); }); }); diff --git a/tests/e2e/specs/devfiles/Quarkus.spec.ts b/tests/e2e/specs/devfiles/Quarkus.spec.ts new file mode 100644 index 000000000000..7db19b53e666 --- /dev/null +++ b/tests/e2e/specs/devfiles/Quarkus.spec.ts @@ -0,0 +1,52 @@ +/********************************************************************* + * Copyright (c) 2019 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { SideBarView, ViewSection } from 'monaco-page-objects'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { Logger } from '../../utils/Logger'; + +const stackName: string = 'Java 11 with Quarkus'; +const projectName: string = 'quarkus-quickstarts'; +const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); +const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); +const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + +suite(`The ${stackName} userstory`, async function () { + let projectSection: ViewSection; + suite(`Create workspace from ${stackName} simple`, async function () { + loginTests.loginIntoChe(); + workspaceHandlingTests.createAndOpenWorkspace(stackName); + workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + test('Register running workspace', async () => { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + test('Wait workspace readiness', async function () { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + test('Check a project folder has been created', async function () { + projectSection = await new SideBarView().getContent().getSection(projectName); + Logger.debug(`new SideBarView().getContent().getSection: get ${projectName}`); + }); + test('Check the project files was imported', async function () { + const label: string = 'devfile.yaml'; + await projectSection.findItem(label); + Logger.debug(`projectSection.findItem: find ${label}`); + }); + test('Stopping and deleting the workspace', async function () { + await workspaceHandlingTests.stopAndRemoveWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + loginTests.logoutFromChe(); + }); +}); diff --git a/tests/e2e/specs/factory/Factory.spec.ts b/tests/e2e/specs/factory/Factory.spec.ts new file mode 100644 index 000000000000..53771529f2be --- /dev/null +++ b/tests/e2e/specs/factory/Factory.spec.ts @@ -0,0 +1,199 @@ +/********************************************************************* + * Copyright (c) 2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import 'reflect-metadata'; + +import { e2eContainer } from '../../configs/inversify.config'; +import { + ActivityBar, + ContextMenu, + EditorView, + Locators, + ModalDialog, + NewScmView, + SideBarView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewItem, + ViewSection +} from 'monaco-page-objects'; +import { TestConstants } from '../../constants/TestConstants'; +import { expect } from 'chai'; +import { OauthPage } from '../../pageobjects/git-providers/OauthPage'; +import { GitUtil } from '../../utils/vsc/GitUtil'; +import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { CLASSES } from '../../configs/inversify.types'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { Logger } from '../../utils/Logger'; +import { LoginTests } from '../../tests-library/LoginTests'; + +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.skip(`Create a workspace via launching a factory from the ${TestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository`, async function () { + const oauthPage: OauthPage = new OauthPage(driverHelper); + + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let rest: SingleScmProvider[]; + let scmContextMenu: ContextMenu; + const gitUtilCheCode: GitUtil = new GitUtil(); + + // test specific data + const timeToRefresh: number = 1500; + const changesToCommit: string = (new Date()).getTime().toString(); + const fileToChange: string = 'Date.txt'; + const commitChangesButtonLabel: string = `Commit Changes on "${TestConstants.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}"`; + const refreshButtonLabel: string = 'Refresh'; + const pushItemLabel: string = 'Push'; + const testRepoProjectName: string = gitUtilCheCode.getProjectNameFromGitUrl(TestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL); + + loginTests.loginIntoChe(); + test(`Navigate to the factory URL`, async function () { + await browserTabsUtil.navigateTo(TestConstants.TS_SELENIUM_FACTORY_URL()); + }); + + if (TestConstants.TS_SELENIUM_GIT_PROVIDER_OAUTH) { + test(`Authorize with a ${TestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} OAuth`, async function () { + await oauthPage.login(); + await oauthPage.waitOauthPage(); + await oauthPage.confirmAccess(); + }); + } + + workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + + test('Registering the running workspace', async function () { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Wait the workspace readiness', async function () { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + + test('Check if a project folder has been created', async function () { + Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); + projectSection = await new SideBarView().getContent().getSection(testRepoProjectName as unknown as string); + }); + + test('Check if the project files were imported', async function () { + const label: string = TestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME; + Logger.debug(`projectSection.findItem: find ${label}`); + const isFileImported: ViewItem | undefined = await projectSection.findItem(label); + expect(isFileImported).not.eqls(undefined); + }); + + test('Accept the project as a trusted one', async function () { + const buttonYesITrustTheAuthors: string = `Yes, I trust the authors`; + const trustedProjectDialog: ModalDialog = new ModalDialog(); + await driverHelper.waitVisibility(webCheCodeLocators.WelcomeContent.button); + Logger.debug(`trustedProjectDialog.pushButton: "${buttonYesITrustTheAuthors}"`); + await trustedProjectDialog.pushButton(buttonYesITrustTheAuthors); + }); + + test('Make changes to the file', async function () { + Logger.debug(`projectSection.openItem: "${fileToChange}"`); + await projectSection.openItem(fileToChange); + const editor: TextEditor = await new EditorView().openEditor(fileToChange) as TextEditor; + await driverHelper.waitVisibility(webCheCodeLocators.Editor.inputArea); + Logger.debug(`editor.clearText`); + await editor.clearText(); + Logger.debug(`editor.typeTextAt: "${changesToCommit}"`); + await editor.typeTextAt(1, 1, changesToCommit); + }); + + test('Open a source control manager', async function () { + const viewSourceControl: string = `Source Control`; + const sourceControl: ViewControl = await new ActivityBar().getViewControl(viewSourceControl) as ViewControl; + Logger.debug(`sourceControl.openView: "${viewSourceControl}"`); + await sourceControl.openView(); + const scmView: NewScmView = new NewScmView(); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); + [scmProvider, ...rest] = await scmView.getProviders(); + Logger.debug(`scmView.getProviders: "${scmProvider}, ${scmProvider}"`); + }); + + test('Check if the changes is displayed in the source control manager', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + await driverHelper.wait(timeToRefresh); + Logger.debug(`scmProvider.takeAction: "${refreshButtonLabel}"`); + await scmProvider.takeAction(refreshButtonLabel); + // wait while changes counter will be refreshed + await driverHelper.wait(timeToRefresh); + const changes: number = await scmProvider.getChangeCount(); + Logger.debug(`scmProvider.getChangeCount: number of changes is "${changes}"`); + expect(changes).eql(1); + }); + + test('Stage the changes', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + Logger.debug(`scmProvider.openMoreActions`); + scmContextMenu = await scmProvider.openMoreActions(); + await driverHelper.waitVisibility(webCheCodeLocators.ContextMenu.contextView); + Logger.debug(`scmContextMenu.select: "Changes" -> "Stage All Changes"`); + await scmContextMenu.select('Changes', 'Stage All Changes'); + }); + + test('Commit the changes', async function () { + 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); + await driverHelper.wait(timeToRefresh); + Logger.debug(`scmProvider.takeAction: "${refreshButtonLabel}"`); + await scmProvider.takeAction(refreshButtonLabel); + // wait while changes counter will be refreshed + await driverHelper.wait(timeToRefresh); + const changes: number = await scmProvider.getChangeCount(); + Logger.debug(`scmProvider.getChangeCount: number of changes is "${changes}"`); + expect(changes).eql(0); + }); + + test('Push the changes', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(`Push 1 commits to origin/${TestConstants.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}`)); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + Logger.debug(`scmProvider.openMoreActions`); + scmContextMenu = await scmProvider.openMoreActions(); + await driverHelper.waitVisibility(webCheCodeLocators.ContextMenu.itemConstructor(pushItemLabel)); + Logger.debug(`scmContextMenu.select: "${pushItemLabel}"`); + await scmContextMenu.select(pushItemLabel); + }); + + test('Check if the changes were pushed', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + await driverHelper.wait(timeToRefresh); + Logger.debug(`scmProvider.takeAction: "${refreshButtonLabel}"`); + await scmProvider.takeAction(refreshButtonLabel); + const isCommitButtonDisabled: string = await driverHelper.waitAndGetElementAttribute(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel), 'aria-disabled'); + expect(isCommitButtonDisabled).eql('true'); + }); + + test(`Stop and remove the workspace`, async function () { + await workspaceHandlingTests.stopAndRemoveWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + loginTests.logoutFromChe(); + + suiteTeardown('Close the browser', async function () { + if (!TestConstants.TS_DEBUG_MODE) { + await driverHelper.getDriver().close(); + } + }); +}); diff --git a/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts new file mode 100644 index 000000000000..4be77c2b8961 --- /dev/null +++ b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts @@ -0,0 +1,272 @@ +/********************************************************************* + * Copyright (c) 2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import 'reflect-metadata'; +import { e2eContainer } from '../../configs/inversify.config'; +import { + ActivityBar, + ContextMenu, + EditorView, + error, + InputBox, + Locators, + ModalDialog, + NewScmView, + SideBarView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewItem, + ViewSection +} from 'monaco-page-objects'; +import { expect } from 'chai'; +import { GitUtil } from '../../utils/vsc/GitUtil'; +import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; +import WebDriverError = error.WebDriverError; +import { registerRunningWorkspace } from '../MochaHooks'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { CLASSES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +import { Workspaces } from '../../pageobjects/dashboard/Workspaces'; +import { GitProviderType, TestConstants } from '../../constants/TestConstants'; +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { Logger } from '../../utils/Logger'; +import { LoginTests } from '../../tests-library/LoginTests'; + +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 ${TestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository without OAuth setup`, async function () { + + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let rest: SingleScmProvider[]; + let scmContextMenu: ContextMenu; + const gitUtilCheCode: GitUtil = new GitUtil(); + + // test specific data + let numberOfCreatedWorkspaces: number = 0; + const timeToRefresh: number = 1500; + const changesToCommit: string = (new Date()).getTime().toString(); + const fileToChange: string = 'Date.txt'; + const pushItemLabel: string = 'Push'; + const commitChangesButtonLabel: string = `Commit Changes on "${TestConstants.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}"`; + const refreshButtonLabel: string = 'Refresh'; + const label: string = TestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME; + const testRepoProjectName: string = gitUtilCheCode.getProjectNameFromGitUrl(TestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL); + const isPrivateRepo: string = TestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO ? 'private' : 'public'; + + loginTests.loginIntoChe(); + + test('Get number of previously created workspaces', async function () { + await dashboard.clickWorkspacesButton(); + await workspaces.waitPage(); + numberOfCreatedWorkspaces = (await workspaces.getAllCreatedWorkspacesNames()).length; + }); + + test(`Navigate to the ${isPrivateRepo} repository factory URL`, async function () { + await browserTabsUtil.navigateTo(TestConstants.TS_SELENIUM_FACTORY_URL()); + }); + + if (TestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + + test(`Check that workspace cannot be created without OAuth for ${isPrivateRepo} repo`, async function () { + await dashboard.waitLoader(); + const loaderAlert: string = await dashboard.getLoaderAlert(); + expect(loaderAlert).contains('Failed to create the workspace') + .and.contains('Cause: Unsupported OAuth provider '); + }); + + test(`Check that workspace was not created`, async function () { + await dashboard.openDashboard(); + await dashboard.clickWorkspacesButton(); + await workspaces.waitPage(); + const allCreatedWorkspacesNames: string[] = await workspaces.getAllCreatedWorkspacesNames(); + expect(allCreatedWorkspacesNames).has.length(numberOfCreatedWorkspaces); + }); + + loginTests.logoutFromChe(); + + } else { + workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + + test('Registering the running workspace', async function () { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Wait the workspace readiness', async function () { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + + test('Check if a project folder has been created', async function () { + Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); + projectSection = await new SideBarView().getContent().getSection(testRepoProjectName as unknown as string); + }); + + test('Accept the project as a trusted one', async function () { + // click somewhere to trigger "Welcome Content" dialog + try { + await driverHelper.waitAndClick(webCheCodeLocators.Workbench.notificationItem); + } catch (e) { + Logger.info(`Click on ${webCheCodeLocators.Workbench.notificationItem} to get "Welcome Content" dialog ${e as string}`); + } + // "Welcome Content" dialog can be shown before of after dialog with an error for private repo + try { + const buttonYesITrustTheAuthors: string = `Yes, I trust the authors`; + await driverHelper.waitVisibility(webCheCodeLocators.WelcomeContent.text, TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM); + const welcomeContentDialog: ModalDialog = new ModalDialog(); + Logger.debug(`trustedProjectDialog.pushButton: "${buttonYesITrustTheAuthors}"`); + await welcomeContentDialog.pushButton(buttonYesITrustTheAuthors); + await driverHelper.waitDisappearance(webCheCodeLocators.WelcomeContent.text); + } catch (e) { + Logger.info(`"Accept the project as a trusted one" dialog was not shown firstly for "${isPrivateRepo}"`); + if (!TestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + throw new WebDriverError(e as string); + } + } + }); + + test('Check if the project files were imported', async function () { + Logger.debug(`projectSection.findItem: find ${label}`); + const isFileImported: ViewItem | undefined = await projectSection.findItem(label); + // projectSection.findItem(label) can return undefined but test will goes on + expect(isFileImported).not.eqls(undefined); + }); + + test('Make changes to the file', async function () { + Logger.debug(`projectSection.openItem: "${fileToChange}"`); + await projectSection.openItem(fileToChange); + const editor: TextEditor = await new EditorView().openEditor(fileToChange) as TextEditor; + await driverHelper.waitVisibility(webCheCodeLocators.Editor.inputArea); + Logger.debug(`editor.clearText`); + await editor.clearText(); + Logger.debug(`editor.typeTextAt: "${changesToCommit}"`); + await editor.typeTextAt(1, 1, changesToCommit); + }); + + test('Open a source control manager', async function () { + const viewSourceControl: string = `Source Control`; + const sourceControl: ViewControl = await new ActivityBar().getViewControl(viewSourceControl) as ViewControl; + Logger.debug(`sourceControl.openView: "${viewSourceControl}"`); + await sourceControl.openView(); + const scmView: NewScmView = new NewScmView(); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); + [scmProvider, ...rest] = await scmView.getProviders(); + Logger.debug(`scmView.getProviders: "${scmProvider}, ${scmProvider}"`); + }); + + test('Check if the changes is displayed in the source control manager', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + await driverHelper.wait(timeToRefresh); + Logger.debug(`scmProvider.takeAction: "${refreshButtonLabel}"`); + await scmProvider.takeAction(refreshButtonLabel); + // wait while changes counter will be refreshed + await driverHelper.wait(timeToRefresh); + const changes: number = await scmProvider.getChangeCount(); + Logger.debug(`scmProvider.getChangeCount: number of changes is "${changes}"`); + expect(changes).eql(1); + }); + + test('Stage the changes', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + Logger.debug(`scmProvider.openMoreActions`); + scmContextMenu = await scmProvider.openMoreActions(); + await driverHelper.waitVisibility(webCheCodeLocators.ContextMenu.contextView); + Logger.debug(`scmContextMenu.select: "Changes" -> "Stage All Changes"`); + await scmContextMenu.select('Changes', 'Stage All Changes'); + }); + + test('Commit the changes', async function () { + 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); + await driverHelper.wait(timeToRefresh); + Logger.debug(`scmProvider.takeAction: "${refreshButtonLabel}"`); + await scmProvider.takeAction(refreshButtonLabel); + // wait while changes counter will be refreshed + await driverHelper.wait(timeToRefresh); + const changes: number = await scmProvider.getChangeCount(); + Logger.debug(`scmProvider.getChangeCount: number of changes is "${changes}"`); + expect(changes).eql(0); + }); + + test('Push the changes', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(`Push 1 commits to origin/${TestConstants.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}`)); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + Logger.debug(`scmProvider.openMoreActions`); + scmContextMenu = await scmProvider.openMoreActions(); + await driverHelper.waitVisibility(webCheCodeLocators.ContextMenu.itemConstructor(pushItemLabel)); + Logger.debug(`scmContextMenu.select: "${pushItemLabel}"`); + await scmContextMenu.select(pushItemLabel); + }); + + if (TestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.GITHUB) { + test('Decline GitHub Extension', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.Dialog.details); + const gitHaExtensionDialog: ModalDialog = new ModalDialog(); + await gitHaExtensionDialog.pushButton('Cancel'); + }); + } + + test('Insert git credentials which were asked after push', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + + try { + await driverHelper.waitVisibility(webCheCodeLocators.Input.inputBox); + } catch (e) { + Logger.info(`Workspace did not ask credentials before push - ${e}; + Known issue for github.com - https://issues.redhat.com/browse/CRW-4066`); + } + const input: InputBox = new InputBox(); + await input.setText(TestConstants.TS_SELENIUM_GIT_PROVIDER_USERNAME); + await driverHelper.wait(timeToRefresh); + await input.confirm(); + await driverHelper.wait(timeToRefresh); + await input.setText(TestConstants.TS_SELENIUM_GIT_PROVIDER_PASSWORD); + await input.confirm(); + await driverHelper.wait(timeToRefresh); + }); + + test('Check if the changes were pushed', async function () { + try { + Logger.debug(`scmProvider.takeAction: "${refreshButtonLabel}"`); + await scmProvider.takeAction(refreshButtonLabel); + } catch (e) { + Logger.info('Check you use correct credentials.' + + 'For bitbucket.org ensure you use an app password: https://support.atlassian.com/bitbucket-cloud/docs/using-app-passwords/;' + + 'For github.com - personal access token instead of password.'); + } + const isCommitButtonDisabled: string = await driverHelper.waitAndGetElementAttribute(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel), 'aria-disabled'); + expect(isCommitButtonDisabled).eql('true'); + }); + + test(`Stop and remove the workspace`, async function () { + await workspaceHandlingTests.stopAndRemoveWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + loginTests.logoutFromChe(); + } + + suiteTeardown('Close the browser', async function () { + if (!TestConstants.TS_DEBUG_MODE) { + await driverHelper.getDriver().close(); + } + }); +}); diff --git a/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts new file mode 100644 index 000000000000..fb176ca1c56c --- /dev/null +++ b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts @@ -0,0 +1,260 @@ +/********************************************************************* + * Copyright (c) 2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import 'reflect-metadata'; +import { e2eContainer } from '../../configs/inversify.config'; +import { + ActivityBar, + ContextMenu, + EditorView, + error, + InputBox, + Locators, + ModalDialog, + NewScmView, + SideBarView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewItem, + ViewSection +} from 'monaco-page-objects'; +import { expect } from 'chai'; +import WebDriverError = error.WebDriverError; +import { registerRunningWorkspace } from '../MochaHooks'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { CLASSES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { TestConstants } from '../../constants/TestConstants'; +import { OauthPage } from '../../pageobjects/git-providers/OauthPage'; +import { GitUtil } from '../../utils/vsc/GitUtil'; +import { Logger } from '../../utils/Logger'; +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { LoginTests } from '../../tests-library/LoginTests'; + +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.skip(`Create a workspace via launching a factory from the ${TestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository and deny the access`, async function () { + const oauthPage: OauthPage = new OauthPage(driverHelper); + + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let rest: SingleScmProvider[]; + let scmContextMenu: ContextMenu; + const gitUtil: GitUtil = new GitUtil(); + + // test specific data + const timeToRefresh: number = 1500; + const changesToCommit: string = (new Date()).getTime().toString(); + const fileToChange: string = 'Date.txt'; + const commitChangesButtonLabel: string = `Commit Changes on "${TestConstants.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}"`; + const refreshButtonLabel: string = 'Refresh'; + const pushItemLabel: string = 'Push'; + const label: string = TestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME; + const testRepoProjectName: string = gitUtil.getProjectNameFromGitUrl(TestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL); + const isPrivateRepo: string = TestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO ? 'private' : 'public'; + + loginTests.loginIntoChe(); + + test(`Navigate to the ${isPrivateRepo} repository factory URL`, async function () { + await browserTabsUtil.navigateTo(TestConstants.TS_SELENIUM_FACTORY_URL()); + }); + + if (TestConstants.TS_SELENIUM_GIT_PROVIDER_OAUTH) { + test(`Authorize with a ${TestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} OAuth and deny access`, async function () { + await oauthPage.login(); + await oauthPage.waitOauthPage(); + await oauthPage.denyAccess(); + }); + } + + workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + + test('The workspace starts with access deny flag in the url', async function () { + expect(await driverHelper.getDriver().getCurrentUrl()).contains('&error_code=access_denied'); + }); + + test('Registering the running workspace', async function () { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Wait the workspace readiness', async function () { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + + test('Check if a project folder has been created', async function () { + Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); + projectSection = await new SideBarView().getContent().getSection(testRepoProjectName as unknown as string); + }); + + test('Accept the project as a trusted one', async function () { + // click somewhere to trigger "Welcome Content" dialog + try { + await driverHelper.waitAndClick(webCheCodeLocators.Workbench.notificationItem); + } catch (e) { + Logger.info(`Click on ${webCheCodeLocators.Workbench.notificationItem} to get "Welcome Content" dialog ${e as string}`); + } + // "Welcome Content" dialog can be shown before of after dialog with an error for private repo + try { + const buttonYesITrustTheAuthors: string = `Yes, I trust the authors`; + await driverHelper.waitVisibility(webCheCodeLocators.WelcomeContent.text, TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM); + const welcomeContentDialog: ModalDialog = new ModalDialog(); + Logger.debug(`trustedProjectDialog.pushButton: "${buttonYesITrustTheAuthors}"`); + await welcomeContentDialog.pushButton(buttonYesITrustTheAuthors); + await driverHelper.waitDisappearance(webCheCodeLocators.WelcomeContent.text); + } catch (e) { + Logger.info(`"Accept the project as a trusted one" dialog was not shown firstly for "${isPrivateRepo}"`); + if (!TestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + throw new WebDriverError(e as string); + } + } + }); + + if (TestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + test('Check that project can not be cloned', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.Dialog.message); + const workspaceDoesNotExistDialog: ModalDialog = new ModalDialog(); + const message: string = await workspaceDoesNotExistDialog.getMessage(); + expect(message).contains('space does not exist'); + }); + + test('Check that project files were not imported', async function () { + const isFileImported: ViewItem | undefined = await projectSection.findItem(label); + expect(isFileImported).eqls(undefined); + }); + + } else { + test('Check if the project files were imported', async function () { + Logger.debug(`projectSection.findItem: find ${label}`); + const isFileImported: ViewItem | undefined = await projectSection.findItem(label); + // projectSection.findItem(label) can return undefined but test will goes on + expect(isFileImported).not.eqls(undefined); + }); + + test('Make changes to the file', async function () { + Logger.debug(`projectSection.openItem: "${fileToChange}"`); + await projectSection.openItem(fileToChange); + const editor: TextEditor = await new EditorView().openEditor(fileToChange) as TextEditor; + await driverHelper.waitVisibility(webCheCodeLocators.Editor.inputArea); + Logger.debug(`editor.clearText`); + await editor.clearText(); + Logger.debug(`editor.typeTextAt: "${changesToCommit}"`); + await editor.typeTextAt(1, 1, changesToCommit); + }); + + test('Open a source control manager', async function () { + const viewSourceControl: string = `Source Control`; + const sourceControl: ViewControl = await new ActivityBar().getViewControl(viewSourceControl) as ViewControl; + Logger.debug(`sourceControl.openView: "${viewSourceControl}"`); + await sourceControl.openView(); + const scmView: NewScmView = new NewScmView(); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); + [scmProvider, ...rest] = await scmView.getProviders(); + Logger.debug(`scmView.getProviders: "${scmProvider}, ${scmProvider}"`); + }); + + test('Check if the changes is displayed in the source control manager', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + await driverHelper.wait(timeToRefresh); + Logger.debug(`scmProvider.takeAction: "${refreshButtonLabel}"`); + await scmProvider.takeAction(refreshButtonLabel); + // wait while changes counter will be refreshed + await driverHelper.wait(timeToRefresh); + const changes: number = await scmProvider.getChangeCount(); + Logger.debug(`scmProvider.getChangeCount: number of changes is "${changes}"`); + expect(changes).eql(1); + }); + + test('Stage the changes', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + Logger.debug(`scmProvider.openMoreActions`); + scmContextMenu = await scmProvider.openMoreActions(); + await driverHelper.waitVisibility(webCheCodeLocators.ContextMenu.contextView); + Logger.debug(`scmContextMenu.select: "Changes" -> "Stage All Changes"`); + await scmContextMenu.select('Changes', 'Stage All Changes'); + }); + + test('Commit the changes', async function () { + 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); + await driverHelper.wait(timeToRefresh); + Logger.debug(`scmProvider.takeAction: "${refreshButtonLabel}"`); + await scmProvider.takeAction(refreshButtonLabel); + // wait while changes counter will be refreshed + await driverHelper.wait(timeToRefresh); + const changes: number = await scmProvider.getChangeCount(); + Logger.debug(`scmProvider.getChangeCount: number of changes is "${changes}"`); + expect(changes).eql(0); + }); + + test('Push the changes', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(`Push 1 commits to origin/${TestConstants.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}`)); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + Logger.debug(`scmProvider.openMoreActions`); + scmContextMenu = await scmProvider.openMoreActions(); + await driverHelper.waitVisibility(webCheCodeLocators.ContextMenu.itemConstructor(pushItemLabel)); + Logger.debug(`scmContextMenu.select: "${pushItemLabel}"`); + await scmContextMenu.select(pushItemLabel); + }); + + test('Insert git credentials which were asked after push', async function () { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + + try { + await driverHelper.waitVisibility(webCheCodeLocators.Input.inputBox); + } catch (e) { + Logger.info(`Workspace did not ask credentials before push - ${e}; + Known issue for github.com - https://issues.redhat.com/browse/CRW-4066`); + } + const input: InputBox = new InputBox(); + await input.setText(TestConstants.TS_SELENIUM_GIT_PROVIDER_USERNAME); + await input.confirm(); + await driverHelper.wait(timeToRefresh); + await input.setText(TestConstants.TS_SELENIUM_GIT_PROVIDER_PASSWORD); + await input.confirm(); + await driverHelper.wait(timeToRefresh); + }); + + test('Check if the changes were pushed', async function () { + try { + Logger.debug(`scmProvider.takeAction: "${refreshButtonLabel}"`); + await scmProvider.takeAction(refreshButtonLabel); + } catch (e) { + Logger.info('Check you use correct credentials.' + + 'For bitbucket.org ensure you use an app password: https://support.atlassian.com/bitbucket-cloud/docs/using-app-passwords/;' + + 'For github.com - personal access token instead of password.'); + } + const isCommitButtonDisabled: string = await driverHelper.waitAndGetElementAttribute(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel), 'aria-disabled'); + expect(isCommitButtonDisabled).eql('true'); + }); + } + + test(`Stop and remove the workspace`, async function () { + await workspaceHandlingTests.stopAndRemoveWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + loginTests.logoutFromChe(); + + suiteTeardown('Close the browser', async function () { + if (!TestConstants.TS_DEBUG_MODE) { + await driverHelper.getDriver().close(); + } + }); +}); diff --git a/tests/e2e/specs/login/LinkCheAndOcpUsers.spec.ts b/tests/e2e/specs/login/LinkCheAndOcpUsers.spec.ts deleted file mode 100644 index 71df91125f11..000000000000 --- a/tests/e2e/specs/login/LinkCheAndOcpUsers.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - **********************************************************************/ - -import { CLASSES, TYPES } from '../../configs/inversify.types'; -import { e2eContainer } from '../../configs/inversify.config'; -import { IOcpLoginPage } from '../../pageobjects/login/IOcpLoginPage'; -import { UpdateAccountInformationPage } from '../../pageobjects/login/UpdateAccountInformationPage'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; -import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; -import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; -import { TestConstants } from '../../constants/TestConstants'; - -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -const ocpLogin: IOcpLoginPage = e2eContainer.get(TYPES.OcpLogin); -const updateAccountInformation: UpdateAccountInformationPage = e2eContainer.get(CLASSES.UpdateAccountInformationPage); -const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); - -const commonTimeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT * 2; - -suite('Link users', async () => { - test('Login to OCP', async () => { - await browserTabsUtil.navigateTo(TestConstants.TS_SELENIUM_BASE_URL); - - await ocpLogin.login(); - await updateAccountInformation.clickToAllowSelectedPermissionsButton(commonTimeout); - }); - - test('Update account information', async () => { - await updateAccountInformation.enterEmail('admin@admin.com', commonTimeout); - await updateAccountInformation.enterFirstName(TestConstants.TS_SELENIUM_USERNAME, commonTimeout); - await updateAccountInformation.enterLastName(TestConstants.TS_SELENIUM_USERNAME, commonTimeout); - await updateAccountInformation.clickConfirmButton(commonTimeout); - await updateAccountInformation.clickAddToExistingAccountButton(commonTimeout); - }); - - test('Login to Che', async () => { - await updateAccountInformation.enterPassword(TestConstants.TS_SELENIUM_PASSWORD, commonTimeout); - await updateAccountInformation.clickLogInButton(commonTimeout); - await dashboard.waitPage(commonTimeout); - }); - -}); diff --git a/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts b/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts new file mode 100644 index 000000000000..ab554825376c --- /dev/null +++ b/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts @@ -0,0 +1,74 @@ +import { e2eContainer } from '../../configs/inversify.config'; +import { assert } from 'chai'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { CLASSES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { Logger } from '../../utils/Logger'; +import { LoginTests } from '../../tests-library/LoginTests'; + +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'; + +async function runShellScript(shellCommandToExecution: string): Promise { + const {stdout, stderr} = await exec(shellCommandToExecution); + console.log(stdout); + console.error(stderr); + return stdout; +} + +suite.skip(`Create predefined workspace and check it `, async function () { + 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 < { + const workspaceName: string = WorkspaceHandlingTests.getWorkspaceName(); + try { + await runShellScript(deletePredefinedNamespace); + } catch (e) { + Logger.error(`Cannot remove the predefined project: ${workspaceName}, please fix it manually: ${e}`); + } + }); + + loginTests.loginIntoChe(); + // create the Empty workspace using CHE Dashboard + workspaceHandlingTests.createAndOpenWorkspace('Empty Workspace'); + 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 () { + workspaceName = WorkspaceHandlingTests.getWorkspaceName(); + registerRunningWorkspace(workspaceName); + const ocDevWorkspaceOutput: string = await runShellScript(getDevWorkspaceFromPredefinedNameSpace); + await assert.isTrue(ocDevWorkspaceOutput.includes(workspaceName)); + }); + + loginTests.logoutFromChe(); +}); + + diff --git a/tests/e2e/tests-library/LoginTests.ts b/tests/e2e/tests-library/LoginTests.ts index b36da260f488..2cfcf2bd74d5 100644 --- a/tests/e2e/tests-library/LoginTests.ts +++ b/tests/e2e/tests-library/LoginTests.ts @@ -14,12 +14,14 @@ import { TestConstants } from '../constants/TestConstants'; import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; import { Logger } from '../utils/Logger'; import { inject, injectable } from 'inversify'; +import { Dashboard } from '../pageobjects/dashboard/Dashboard'; @injectable() export class LoginTests { constructor( @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil, - @inject(TYPES.CheLogin) private readonly loginPage: ICheLoginPage) { + @inject(TYPES.CheLogin) private readonly loginPage: ICheLoginPage, + @inject(CLASSES.Dashboard) private readonly dashboard: Dashboard) { } public loginIntoChe(): void { @@ -32,4 +34,10 @@ export class LoginTests { } }); } + + public logoutFromChe(): void { + test('Logout', async () => { + await this.dashboard.logout(); + }); + } } diff --git a/tests/e2e/tests-library/WorkspaceHandlingTests.ts b/tests/e2e/tests-library/WorkspaceHandlingTests.ts index 1caf7df9a241..7596372996cf 100644 --- a/tests/e2e/tests-library/WorkspaceHandlingTests.ts +++ b/tests/e2e/tests-library/WorkspaceHandlingTests.ts @@ -29,10 +29,6 @@ export class WorkspaceHandlingTests { return WorkspaceHandlingTests.workspaceName; } - public static setWorkspaceName(workspaceName: string): void { - WorkspaceHandlingTests.workspaceName = workspaceName; - } - private static WORKSPACE_NAME_LOCATOR: By = By.xpath(`//h1[contains(.,'Starting workspace ')]`); private static workspaceName: string = 'undefined'; private static parentGUID: string; diff --git a/tests/e2e/utils/BrowserTabsUtil.ts b/tests/e2e/utils/BrowserTabsUtil.ts index 47941abf867b..655dd85fd4eb 100644 --- a/tests/e2e/utils/BrowserTabsUtil.ts +++ b/tests/e2e/utils/BrowserTabsUtil.ts @@ -9,7 +9,6 @@ **********************************************************************/ import { injectable, inject } from 'inversify'; -import { By, error } from 'selenium-webdriver'; import { CLASSES } from '../configs/inversify.types'; import { DriverHelper } from './DriverHelper'; import { Logger } from './Logger'; @@ -60,18 +59,11 @@ export class BrowserTabsUtil { const windowHandles: string[] = await this.getAllWindowHandles(); - windowHandles.forEach(async windowHandle => { + for (const windowHandle of windowHandles) { if (windowHandle !== currentWindowHandle) { await this.switchToWindow(windowHandle); - return; } - }); - } - - async waitContentAvailableInTheNewTab(contentLocator: By, timeout: number) { - Logger.debug('BrowserTabsUtil.waitContentAvailableInTheNewTab'); - - await this.driverHelper.waitVisibility(contentLocator, timeout); + } } async refreshPage() { @@ -80,20 +72,6 @@ export class BrowserTabsUtil { await (await this.driverHelper.getDriver()).navigate().refresh(); } - async refreshForDebug() { - Logger.debug('BrowserTabsUtil.refreshForDebug'); - - // if refresh triggers debug breakpoint test stucks of the refreshing - // and fail with a timeout error. - try { - await (await this.driverHelper.getDriver()).navigate().refresh(); - } catch (err) { - if (!(err instanceof error.TimeoutError)) { - throw err; - } - } - } - async getCurrentUrl(): Promise { return await this.driverHelper.getDriver().getCurrentUrl(); } diff --git a/tests/e2e/utils/DriverHelper.ts b/tests/e2e/utils/DriverHelper.ts index 9772a1be2426..844b5d825d02 100644 --- a/tests/e2e/utils/DriverHelper.ts +++ b/tests/e2e/utils/DriverHelper.ts @@ -10,9 +10,8 @@ import { IDriver } from '../driver/IDriver'; import { inject, injectable } from 'inversify'; import { TYPES } from '../configs/inversify.types'; -import { error, Actions } from 'selenium-webdriver'; +import { Actions, By, error, ThenableWebDriver, until, WebElement } from 'selenium-webdriver'; import 'reflect-metadata'; -import { ThenableWebDriver, By, until, WebElement } from 'selenium-webdriver'; import { TestConstants } from '../constants/TestConstants'; import { Logger } from './Logger'; import { TimeoutConstants } from '../constants/TimeoutConstants'; @@ -32,23 +31,12 @@ export class DriverHelper { return this.driver.actions(); } - /** - * @deprecated Method deprecated. Use the next method instead. - * @see BrowserTabsUtil.maximize() - */ - public async maximize() { - Logger.trace(`DriverHelper.maximize`); - - await this.driver.manage().window().maximize(); - } - public async isVisible(locator: By): Promise { Logger.trace(`DriverHelper.isVisible ${locator}`); try { const element: WebElement = await this.driver.findElement(locator); - const isVisible: boolean = await element.isDisplayed(); - return isVisible; + return await element.isDisplayed(); } catch { return false; } @@ -164,8 +152,7 @@ export class DriverHelper { for (let i = 0; i < attempts; i++) { try { - const webElement: WebElement = await this.driver.wait(until.elementLocated(elementLocator), polling); - return webElement; + return await this.driver.wait(until.elementLocated(elementLocator), polling); } catch (err) { if (err instanceof error.TimeoutError) { Logger.trace(`DriverHelper.waitPresence - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); @@ -182,7 +169,7 @@ export class DriverHelper { } } - throw new error.TimeoutError(`Exceeded maximum presence checkings attempts, problems with 'StaleElementReferenceError' of '${elementLocator}' element`); + throw new error.TimeoutError(`Exceeded maximum presence checking attempts, problems with 'StaleElementReferenceError' of '${elementLocator}' element`); } public async waitAllPresence(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise> { @@ -193,8 +180,7 @@ export class DriverHelper { for (let i = 0; i < attempts; i++) { try { - const webElements: Array = await this.driver.wait(until.elementsLocated(elementLocator), polling); - return webElements; + return await this.driver.wait(until.elementsLocated(elementLocator), polling); } catch (err) { if (err instanceof error.TimeoutError) { Logger.trace(`DriverHelper.waitAllPresence - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); @@ -299,7 +285,6 @@ export class DriverHelper { } throw new error.TimeoutError(`Exceeded maximum clicking attempts, the '${elementLocator}' element is not clickable`); - } public async waitAndGetElementAttribute(elementLocator: By, attribute: string, @@ -329,8 +314,7 @@ export class DriverHelper { } try { - const attributeValue = await element.getAttribute(attribute); - return attributeValue; + return await element.getAttribute(attribute); } catch (err) { if (err instanceof error.StaleElementReferenceError) { await this.wait(polling); @@ -372,8 +356,7 @@ export class DriverHelper { } try { - const cssAttributeValue = await element.getCssValue(cssAttribute); - return cssAttributeValue; + return await element.getCssValue(cssAttribute); } catch (err) { if (err instanceof error.StaleElementReferenceError) { await this.wait(polling); @@ -622,8 +605,7 @@ export class DriverHelper { } try { - const innerText: string = await element.getText(); - return innerText; + return await element.getText(); } catch (err) { if (err instanceof error.StaleElementReferenceError) { await this.wait(polling); @@ -641,8 +623,7 @@ export class DriverHelper { public async waitAndGetValue(elementLocator: By, timeout: number): Promise { Logger.trace(`DriverHelper.waitAndGetValue ${elementLocator}`); - const elementValue: string = await this.waitAndGetElementAttribute(elementLocator, 'value', timeout); - return elementValue; + return await this.waitAndGetElementAttribute(elementLocator, 'value', timeout); } public async waitUntilTrue(callback: any, timeout: number) { @@ -651,54 +632,6 @@ export class DriverHelper { await this.driver.wait(callback, timeout); } - /** - * @deprecated Method deprecated. Use the next method instead. - * @see BrowserTabsUtil.refreshPage() - */ - public async reloadPage() { - Logger.debug('DriverHelper.reloadPage'); - - await this.driver.navigate().refresh(); - } - - /** - * @deprecated Method deprecated. Use the next method instead. - * @see BrowserTabsUtil.navigateAndWaitToUrl() - */ - public async navigateAndWaitToUrl(url: string, timeout: number = TimeoutConstants.TS_SELENIUM_WAIT_FOR_URL) { - Logger.trace(`DriverHelper.navigateAndWaitToUrl ${url}`); - - await this.navigateToUrl(url); - await this.waitURL(url, timeout); - } - - /** - * @deprecated Method deprecated. Use the next method instead. - * @see BrowserTabsUtil.navigateTo() - */ - public async navigateToUrl(url: string) { - Logger.debug(`DriverHelper.navigateToUrl ${url}`); - - await this.driver.navigate().to(url); - } - - /** - * @deprecated Method deprecated. Use the next method instead. - * @see BrowserTabsUtil.waitURL() - */ - public async waitURL(expectedUrl: string, timeout: number) { - Logger.trace(`DriverHelper.waitURL ${expectedUrl}`); - - await this.getDriver().wait(async () => { - const currentUrl: string = await this.getDriver().getCurrentUrl(); - const urlEquals: boolean = currentUrl === expectedUrl; - - if (urlEquals) { - return true; - } - }, timeout); - } - public async scrollTo(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM) { const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING; const attempts: number = Math.ceil(timeout / polling); @@ -741,14 +674,6 @@ export class DriverHelper { throw new error.TimeoutError(`Exceeded maximum mouse move attempts, for the '${elementLocator}' element`); } - /** - * @deprecated Method deprecated. Use the next method instead. - * @see BrowserTabsUtil.getCurrentUrl() - */ - public async getCurrentUrl(): Promise { - return await this.driver.getCurrentUrl(); - } - getDriver(): ThenableWebDriver { Logger.trace('DriverHelper.getDriver'); diff --git a/tests/e2e/utils/Logger.ts b/tests/e2e/utils/Logger.ts index e0e8c053c367..509dca3e6bea 100644 --- a/tests/e2e/utils/Logger.ts +++ b/tests/e2e/utils/Logger.ts @@ -15,6 +15,7 @@ export abstract class Logger { /** * Uses for logging of fatal errors. * @param text log text + * @param indentLevel log level */ public static error(text: string, indentLevel: number = 1) { this.logText(indentLevel, `[ERROR] ${text}`); @@ -23,6 +24,7 @@ export abstract class Logger { /** * Uses for logging of recoverable errors and general warnings. * @param text log text + * @param indentLevel log level */ public static warn(text: string, indentLevel: number = 1) { if (TestConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR') { @@ -34,6 +36,7 @@ export abstract class Logger { /** * Uses for logging of the public methods of the pageobjects. * @param text log text + * @param indentLevel log level */ public static info(text: string, indentLevel: number = 3) { if (TestConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR' || @@ -46,6 +49,7 @@ export abstract class Logger { /** * Uses for logging of the public methods of the pageobjects. * @param text log text + * @param indentLevel log level */ public static debug(text: string, indentLevel: number = 5) { if (TestConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR' || @@ -60,6 +64,7 @@ export abstract class Logger { * Uses for logging of the public methods of the {@link DriverHelper} or * private methods inside of pageobjects. * @param text log text + * @param indentLevel log level */ public static trace(text: string, indentLevel: number = 6) { if (TestConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR' || diff --git a/tests/e2e/utils/Sanitizer.ts b/tests/e2e/utils/Sanitizer.ts index ffe75ba2b33a..6776ad7aa00a 100644 --- a/tests/e2e/utils/Sanitizer.ts +++ b/tests/e2e/utils/Sanitizer.ts @@ -16,5 +16,4 @@ export class Sanitizer { public sanitize(arg: string): string { return arg.replace(/[\/]/g, '+').replace(/[\,]/g, '.').replace(/[\:]/g, '-').replace(/[\'\"]/g, '').replace(/[^a-z0-9\+\-\.\(\)\[\]\_]/gi, '_'); } - } diff --git a/tests/e2e/utils/WorkspaceNameHandler.ts b/tests/e2e/utils/WorkspaceNameHandler.ts deleted file mode 100644 index 7b14dad1471c..000000000000 --- a/tests/e2e/utils/WorkspaceNameHandler.ts +++ /dev/null @@ -1,48 +0,0 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - **********************************************************************/ - -import { CLASSES } from '../configs/inversify.types'; -import { inject, injectable } from 'inversify'; -import { BrowserTabsUtil } from './BrowserTabsUtil'; -import { Logger } from './Logger'; - -@injectable() -export class WorkspaceNameHandler { - - constructor(@inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil) {} - - public generateWorkspaceName(prefix: string, randomLength: number): string { - const possibleCharacters: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - const possibleCharactersLength: number = possibleCharacters.length; - let randomPart: string = ''; - Logger.debug('WorkspaceNameHandler.generateWorkspaceName'); - - for (let i = 0; i < randomLength; i++) { - let currentRandomIndex: number = Math.floor(Math.random() * Math.floor(possibleCharactersLength)); - - randomPart += possibleCharacters[currentRandomIndex]; - } - - return prefix + randomPart; - } - - public async getNameFromUrl(): Promise { - let workspaceUrl: string = await this.browserTabsUtil.getCurrentUrl(); - Logger.debug(`WorkspaceNameHandler.fromWorkspaceUrl workspaceUrl: ${workspaceUrl}`); - - const workspaceUrlParts: string[] = workspaceUrl.split('/'); - const workspaceNameQueryString: string = workspaceUrlParts[workspaceUrlParts.length - 1]; - const workspaceName: string = workspaceNameQueryString.split('?')[0]; - - Logger.debug(`workspaceName: ${workspaceName}`); - - return workspaceName; - } -} diff --git a/tests/e2e/utils/request-handlers/CheApiRequestHandler.ts b/tests/e2e/utils/request-handlers/CheApiRequestHandler.ts index cb9d253a01bc..873aaae2f683 100644 --- a/tests/e2e/utils/request-handlers/CheApiRequestHandler.ts +++ b/tests/e2e/utils/request-handlers/CheApiRequestHandler.ts @@ -21,7 +21,7 @@ export class CheApiRequestHandler { /** * This method adds a request interceptor into axios request interceptors list and returns an ID of the interceptor */ - public static enableRequestInteceptor(): number { + public static enableRequestInterceptor(): number { Logger.debug(`CheApiRequestHandler.enableRequestInterceptor`); return axios.interceptors.request.use( request => { try { diff --git a/tests/e2e/utils/request-handlers/tokens/CheMultiuserTokenHandler.ts b/tests/e2e/utils/request-handlers/tokens/CheMultiuserTokenHandler.ts deleted file mode 100644 index 5d7ab81d0e0a..000000000000 --- a/tests/e2e/utils/request-handlers/tokens/CheMultiuserTokenHandler.ts +++ /dev/null @@ -1,41 +0,0 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - **********************************************************************/ -import axios from 'axios'; -import querystring from 'querystring'; -import { injectable } from 'inversify'; -import { TestConstants } from '../../../constants/TestConstants'; -import { ITokenHandler } from './ITokenHandler'; - - -@injectable() -export class CheMultiuserTokenHandler implements ITokenHandler { - async get(): Promise { - // to-do: Login to the che-dashboard and fetch the authorization related info - const keycloakUrl = ''; - - const params = { - client_id: 'che-public', - username: TestConstants.TS_SELENIUM_USERNAME, - password: TestConstants.TS_SELENIUM_PASSWORD, - grant_type: 'password', - }; - - try { - const responseToObtainBearerToken = await axios.post( - keycloakUrl, - querystring.stringify(params) - ); - return responseToObtainBearerToken.data.access_token; - } catch (err) { - console.log(`Can not get bearer token. URL used: ${keycloakUrl}`); - throw err; - } - } -} diff --git a/tests/e2e/utils/request-handlers/tokens/ITokenHandler.ts b/tests/e2e/utils/request-handlers/tokens/ITokenHandler.ts deleted file mode 100644 index b0064077077e..000000000000 --- a/tests/e2e/utils/request-handlers/tokens/ITokenHandler.ts +++ /dev/null @@ -1,14 +0,0 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - **********************************************************************/ - - -export interface ITokenHandler { - get(): Promise; -} diff --git a/tests/e2e/utils/vsc/CheGitApi.ts b/tests/e2e/utils/vsc/CheGitApi.ts deleted file mode 100644 index 3b890379f45f..000000000000 --- a/tests/e2e/utils/vsc/CheGitApi.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { injectable, inject } from 'inversify'; -import { CLASSES } from '../../configs/inversify.types'; -import { CheApiRequestHandler } from '../request-handlers/CheApiRequestHandler'; - - -@injectable() -export class CheGitApi { - static readonly GIT_API_ENTRIPOINT_URL = 'api/ssh/vcs'; - - constructor(@inject(CLASSES.CheApiRequestHandler) private readonly processRequestHandler: CheApiRequestHandler) { } - - public async getPublicSSHKey(): Promise { - - try { - const responce = await this.processRequestHandler.get(CheGitApi.GIT_API_ENTRIPOINT_URL); - return responce.data[0].publicKey; - } catch (error) { - console.error('Cannot get public ssh key with API \n' + error); - throw error; - } - } -} diff --git a/tests/e2e/utils/vsc/GitUtil.ts b/tests/e2e/utils/vsc/GitUtil.ts new file mode 100644 index 000000000000..927b8ed8a989 --- /dev/null +++ b/tests/e2e/utils/vsc/GitUtil.ts @@ -0,0 +1,28 @@ +/********************************************************************* + * Copyright (c) 2019 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 { injectable } from 'inversify'; + +@injectable() +export class GitUtil { + + constructor() { } + + /** + * Method extracts a test repo name from git clone https url; + * it splits the url into string[] by "/" or ".", deletes empty elements and elements that contains just "git" word, than returns the last one; + * please, avoid to call the test repo as just "git" or to use dots in the name, like: github.com/user/git.git, github.com/user/name.with.dots. + * @param url git https url (which using for "git clone") + * @return project name + */ + getProjectNameFromGitUrl(url: string) { + return url.split(/[\/.]/).filter((e: string) => e !== '' && e !== 'git').reverse()[0]; + } +} diff --git a/tests/e2e/utils/vsc/github/GitHubUtil.ts b/tests/e2e/utils/vsc/github/GitHubUtil.ts deleted file mode 100644 index 16551208f414..000000000000 --- a/tests/e2e/utils/vsc/github/GitHubUtil.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { injectable } from 'inversify'; -import axios from 'axios'; - -@injectable() -export class GitHubUtil { - private static readonly GITHUB_API_ENTRIPOINT_URL = 'https://api.github.com/'; - /** - * add public part of ssh key to the defied github account - * @param authToken - * @param title - * @param key - */ - async addPublicSshKeyToUserAccount(authToken: string, title: string, key: string) { - const gitHubApiSshURL: string = GitHubUtil.GITHUB_API_ENTRIPOINT_URL + 'user/keys'; - const authHeader = { headers: { 'Authorization': 'token ' + authToken, 'Content-Type': 'application/json' } }; - - const data = { - title: `${title}`, - key: `${key}` - }; - - try { await axios.post(gitHubApiSshURL, JSON.stringify(data), authHeader); } catch (error) { - console.error('Cannot add the public key to the GitHub account: '); - console.error(error); - throw error; - } - } - - async getRawContentFromFile(pathToFile: string): Promise { - const gitHubContentEntryPointUrl: string = 'https://raw.githubusercontent.com/'; - const pathToRawContent: string = `${gitHubContentEntryPointUrl}${pathToFile}`; - const authorization: string = 'Authorization'; - const contentType: string = 'Content-Type'; - - try { - delete axios.defaults.headers.common[authorization]; - delete axios.defaults.headers.common[contentType]; - const response = await axios.get(`${gitHubContentEntryPointUrl}${pathToFile}`); - return response.data; - } catch (error) { - console.error('Cannot get content form the raw github content: ' + pathToRawContent); - console.error(error); - throw error; - } - } - - async getPublicSshKeys(authToken: string): Promise> { - const gitHubApiSshURL: string = GitHubUtil.GITHUB_API_ENTRIPOINT_URL + 'user/keys'; - const authHeader = { headers: { 'Authorization': 'token ' + authToken, 'Content-Type': 'application/json' } }; - try { - const response = await axios.get(gitHubApiSshURL, authHeader); - const stringified = JSON.stringify(response.data); - const arrayOfWorkspaces = JSON.parse(stringified); - const idOfRunningWorkspace: Array = new Array(); - for (let entry of arrayOfWorkspaces) { - idOfRunningWorkspace.push(entry.id); - } - return idOfRunningWorkspace; - } catch (error) { - console.error('Cannot get public Keys from github: ' + gitHubApiSshURL); - console.error(error); - throw error; - } - } - - async removePublicSshKey(authToken: string, keyId: string) { - const gitHubApiSshURL: string = GitHubUtil.GITHUB_API_ENTRIPOINT_URL + 'user/keys/' + keyId; - const authHeader = { headers: { 'Authorization': 'token ' + authToken, 'Content-Type': 'application/json' } }; - try { await axios.delete(gitHubApiSshURL, authHeader); } catch (error) { - console.error('Cannot delete the public key from the GitHub account: '); - console.error(error); - throw error; - } - } - - async deletePublicSshKeyByName(authToken: string, keyName: string) { - const gitHubApiSshURL: string = GitHubUtil.GITHUB_API_ENTRIPOINT_URL + 'user/keys'; - const authHeader = { headers: { 'Authorization': 'token ' + authToken, 'Content-Type': 'application/json' } }; - try { - const response = await axios.get(gitHubApiSshURL, authHeader); - const stringified = JSON.stringify(response.data); - const arrayOfPublicKeys = JSON.parse(stringified); - for (let entry of arrayOfPublicKeys) { - if (entry.title === keyName) { - await this.removePublicSshKey(authToken, entry.id); - break; - } - } - } catch (error) { - console.error('Cannot delete the ' + keyName + ' public key from the GitHub account'); - console.error(error); - throw error; - } - } - - async removeAllPublicSshKeys(authToken: string) { - try { - const idList: string[] = await this.getPublicSshKeys(authToken); - for (let id of idList) { - await this.removePublicSshKey(authToken, id); - } - - } catch (error) { - console.error('Cannot delete the public key from the GitHub account: '); - console.error(error); - throw error; - } - } - -} diff --git a/tests/e2e/utils/workspace/ApiUrlResolver.ts b/tests/e2e/utils/workspace/ApiUrlResolver.ts index 9e901ddfacbc..2603048b507c 100644 --- a/tests/e2e/utils/workspace/ApiUrlResolver.ts +++ b/tests/e2e/utils/workspace/ApiUrlResolver.ts @@ -30,10 +30,6 @@ export class ApiUrlResolver { return `${ApiUrlResolver.DASHBOARD_API_URL}/${namespace}/devworkspaces`; } - public getKubernetesApiUrl(): string { - return ApiUrlResolver.KUBERNETES_API_URL; - } - private async obtainUserNamespace(): Promise { Logger.debug(`ApiUrlResolver.obtainUserNamespace ${this.userNamespace}`); if (this.userNamespace.length === 0) { diff --git a/tests/e2e/utils/workspace/ITestWorkspaceUtil.ts b/tests/e2e/utils/workspace/ITestWorkspaceUtil.ts index a0d2bb55fadf..29d6f9236645 100644 --- a/tests/e2e/utils/workspace/ITestWorkspaceUtil.ts +++ b/tests/e2e/utils/workspace/ITestWorkspaceUtil.ts @@ -9,7 +9,6 @@ **********************************************************************/ import { WorkspaceStatus } from './WorkspaceStatus'; -import { che } from '@eclipse-che/api'; export interface ITestWorkspaceUtil { waitWorkspaceStatus(namespace: string, workspaceName: string, expectedWorkspaceStatus: WorkspaceStatus): void; @@ -17,7 +16,7 @@ export interface ITestWorkspaceUtil { stopWorkspaceByName(workspaceName: string): void; /** - * Delete a worksapce without stopping phase (similar with force deleting) + * Delete a workspace without stopping phase (similar with force deleting) */ deleteWorkspaceByName(workspaceName: string): void; @@ -41,58 +40,4 @@ export interface ITestWorkspaceUtil { * Similar with 'force' deleting */ deleteAllWorkspaces(namespace: string): void; - - /*===================== - * DEPRECATED METHODS * - *====================*/ - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - cleanUpAllWorkspaces(): void; - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - cleanUpRunningWorkspace(workspaceName: string): void; - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - waitPluginAdding(namespace: string, workspaceName: string, pluginId: string): void; - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - removeWorkspaceById(id: string): void; - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - stopWorkspaceById(id: string): void; - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - getIdOfRunningWorkspace(workspaceName: string): Promise; - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - getIdOfRunningWorkspaces(): Promise>; - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - createWsFromDevFile(customTemplate: che.workspace.devfile.Devfile): void; - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - getBaseDevfile(): Promise; - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - startWorkspace(workspaceId: string): void; } diff --git a/tests/e2e/utils/workspace/TestWorkspaceUtil.ts b/tests/e2e/utils/workspace/TestWorkspaceUtil.ts index 5b851f91e128..e19c8e743146 100644 --- a/tests/e2e/utils/workspace/TestWorkspaceUtil.ts +++ b/tests/e2e/utils/workspace/TestWorkspaceUtil.ts @@ -9,7 +9,6 @@ **********************************************************************/ import 'reflect-metadata'; -import { che } from '@eclipse-che/api'; import { TestConstants } from '../../constants/TestConstants'; import { injectable, inject } from 'inversify'; import { DriverHelper } from '../DriverHelper'; @@ -81,7 +80,7 @@ export class TestWorkspaceUtil implements ITestWorkspaceUtil { await this.waitWorkspaceStatus(workspaceName, WorkspaceStatus.STOPPED); } - // delete a worksapce without stopping phase (similar with force deleting) + // delete a workspace without stopping phase (similar with force deleting) public async deleteWorkspaceByName(workspaceName: string) { Logger.debug(`TestWorkspaceUtil.deleteWorkspaceByName ${workspaceName}` ); @@ -138,7 +137,7 @@ export class TestWorkspaceUtil implements ITestWorkspaceUtil { } } - // stop all run workspaces, check statused and remove the workspaces + // stop all run workspaces, check statuses and remove the workspaces public async stopAndDeleteAllRunningWorkspaces(namespace: string) { Logger.debug('TestWorkspaceUtil.stopAndDeleteAllRunProjects'); let response = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl()); @@ -160,244 +159,4 @@ export class TestWorkspaceUtil implements ITestWorkspaceUtil { await this.deleteWorkspaceByName(response.data.items[i].metadata.name); } } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - public async waitPluginAdding(namespace: string, workspaceName: string, pluginName: string) { - Logger.debug('TestWorkspaceUtil.waitPluginAdding'); - - const workspaceStatusApiUrl: string = `${await this.apiUrlResolver.getWorkspacesApiUrl()}/${namespace}:${workspaceName}`; - const attempts: number = TestConstants.TS_SELENIUM_PLUGIN_PRECENCE_ATTEMPTS; - const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING; - - for (let i = 0; i < attempts; i++) { - const response = await this.processRequestHandler.get(workspaceStatusApiUrl); - - if (response.status !== 200) { - await this.driverHelper.wait(polling); - continue; - } - - const machines: string = JSON.stringify(response.data.runtime.machines); - const isPluginPresent: boolean = machines.search(pluginName) > 0; - - if (isPluginPresent) { - break; - } - - if (i === attempts - 1) { - throw new error.TimeoutError(`Exceeded maximum tries attempts, the '${pluginName}' plugin is not present in the workspace runtime.`); - } - - await this.driverHelper.wait(polling); - } - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - public async getListOfWorkspaceId(): Promise { - Logger.debug('TestWorkspaceUtil.getListOfWorkspaceId'); - - const getAllWorkspacesResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl()); - - interface IMyObj { - id: string; - status: string; - } - - let stringified = JSON.stringify(getAllWorkspacesResponse.data); - let arrayOfWorkspaces = JSON.parse(stringified); - let wsList: Array = []; - - for (let entry of arrayOfWorkspaces) { - wsList.push(entry.id); - } - - return wsList; - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - public async getIdOfRunningWorkspace(wsName: string): Promise { - Logger.debug('TestWorkspaceUtil.getIdOfRunningWorkspace'); - - const getWorkspacesByNameResponse = await this.processRequestHandler.get(`${await this.apiUrlResolver.getWorkspacesApiUrl()}/:${wsName}`); - return getWorkspacesByNameResponse.data.id; - - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - public async getIdOfRunningWorkspaces(): Promise> { - Logger.debug('TestWorkspaceUtil.getIdOfRunningWorkspaces'); - - try { - const getAllWorkspacesResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl()); - - interface IMyObj { - id: string; - status: string; - } - let stringified = JSON.stringify(getAllWorkspacesResponse.data); - let arrayOfWorkspaces = JSON.parse(stringified); - let idOfRunningWorkspace: Array = new Array(); - - for (let entry of arrayOfWorkspaces) { - if (entry.status === 'RUNNING') { - idOfRunningWorkspace.push(entry.id); - } - } - - return idOfRunningWorkspace; - } catch (err) { - console.log(`Getting id of running workspaces failed. URL used: ${await this.apiUrlResolver.getWorkspacesApiUrl()}`); - throw err; - } - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - public async removeWorkspaceById(id: string) { - Logger.debug('TestWorkspaceUtil.removeWorkspaceById'); - - const workspaceIdUrl: string = `${await this.apiUrlResolver.getWorkspacesApiUrl()}/${id}`; - try { - const deleteWorkspaceResponse = await this.processRequestHandler.delete(workspaceIdUrl); - if (deleteWorkspaceResponse.status !== 204) { - throw new Error(`Can not remove workspace. Code: ${deleteWorkspaceResponse.status} Data: ${deleteWorkspaceResponse.data}`); - } - } catch (err) { - console.log(`Removing of workspace failed.`); - throw err; - } - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - public async stopWorkspaceById(id: string) { - Logger.debug('TestWorkspaceUtil.stopWorkspaceById'); - - const stopWorkspaceApiUrl: string = `${await this.apiUrlResolver.getWorkspacesApiUrl()}/${id}`; - let stopWorkspaceResponse; - - try { - stopWorkspaceResponse = await this.processRequestHandler.delete(`${stopWorkspaceApiUrl}`); - } catch (err) { - console.log(`Stop workspace call failed. URL used: ${stopWorkspaceApiUrl}`); - throw err; - } - - if (stopWorkspaceResponse.status !== 200) { - throw new Error(`Can not stop workspace. Code: ${stopWorkspaceResponse.status} Data: ${stopWorkspaceResponse.data}`); - } - - let stopped: boolean = false; - let wsStatus = await this.processRequestHandler.get(stopWorkspaceApiUrl); - for (let i = 0; i < TestConstants.TS_SELENIUM_PLUGIN_PRECENCE_ATTEMPTS; i++) { - wsStatus = await this.processRequestHandler.get(stopWorkspaceApiUrl); - if (wsStatus.data.status === WorkspaceStatus.STOPPED) { - stopped = true; - break; - } - await this.driverHelper.wait(TestConstants.TS_SELENIUM_DEFAULT_POLLING); - } - - if (!stopped) { - let waitTime = TestConstants.TS_SELENIUM_PLUGIN_PRECENCE_ATTEMPTS * TestConstants.TS_SELENIUM_DEFAULT_POLLING; - throw new error.TimeoutError(`The workspace was not stopped in ${waitTime} ms. Currnet status is: ${wsStatus.data.status}`); - } - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - public async cleanUpAllWorkspaces() { - Logger.debug('TestWorkspaceUtil.cleanUpAllWorkspaces'); - - let listOfRunningWorkspaces: Array = await this.getIdOfRunningWorkspaces(); - for (const entry of listOfRunningWorkspaces) { - await this.stopWorkspaceById(entry); - } - - let listAllWorkspaces: Array = await this.getListOfWorkspaceId(); - - for (const entry of listAllWorkspaces) { - await this.removeWorkspaceById(entry); - } - - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - public async cleanUpRunningWorkspace(workspaceName: string) { - if (workspaceName === undefined || workspaceName.length === 0) { - Logger.warn(`Could nod delete workspace because workspaceName is undefined or empty`); - return; - } - - Logger.debug(`TestWorkspaceUtil.cleanUpRunningWorkspace ${workspaceName}`); - const workspaceID: string = await this.getIdOfRunningWorkspace(workspaceName); - - if (workspaceID === undefined || workspaceID.length === 0) { - Logger.error(`Could nod delete workspace with name ${workspaceName} because workspaceID is undefined or empty`); - return; - } - - Logger.trace(`TestWorkspaceUtil.cleanUpRunningWorkspace Stopping workspace:${workspaceName} with ID:${workspaceID}`); - await this.stopWorkspaceById(workspaceID); - Logger.trace(`TestWorkspaceUtil.cleanUpRunningWorkspace Deleting workspace ${workspaceName}`); - await this.removeWorkspaceById(workspaceID); - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - async createWsFromDevFile(customTemplate: che.workspace.devfile.Devfile) { - Logger.debug('TestWorkspaceUtil.createWsFromDevFile'); - - try { - await this.processRequestHandler.post(await this.apiUrlResolver.getWorkspacesApiUrl() + '/devfile', customTemplate); - } catch (error) { - console.error(error); - throw error; - } - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - async getBaseDevfile(): Promise { - Logger.debug('TestWorkspaceUtil.getBaseDevfile'); - - const baseDevfile: che.workspace.devfile.Devfile = { - apiVersion: '1.0.0', - metadata: { - name: 'test-workspace' - } - }; - - return baseDevfile; - } - - /** - * @deprecated Method deprecated. Works with CHE server only - */ - async startWorkspace(workspaceId: string) { - Logger.debug('TestWorkspaceUtil.startWorkspace'); - - try { - await this.processRequestHandler.post(`${await this.apiUrlResolver.getWorkspacesApiUrl()}/${workspaceId}/runtime`); - } catch (error) { - console.error(error); - throw error; - } - } - }