From a82690380c547128f93ff6c6a94cc0c69a858a08 Mon Sep 17 00:00:00 2001 From: mdolhalo Date: Tue, 25 Jul 2023 11:19:48 +0200 Subject: [PATCH] feat: migrating from TSLint to ESLint and formatting with Prettier added pre-commit hook with Husky Signed-off-by: mdolhalo --- .husky/pre-commit | 4 + tests/e2e/.eslintignore | 10 + tests/e2e/.eslintrc.js | 183 + tests/e2e/.prettierignore | 10 + tests/e2e/.prettierrc.json | 10 + tests/e2e/README.md | 94 +- tests/e2e/configs/inversify.config.ts | 22 +- tests/e2e/configs/inversify.types.ts | 58 +- tests/e2e/configs/mocharc.ts | 45 +- tests/e2e/constants/APITestConstants.ts | 57 - tests/e2e/constants/API_TEST_CONSTANTS.ts | 67 + tests/e2e/constants/BASE_TEST_CONSTANTS.ts | 80 + tests/e2e/constants/BaseTestConstants.ts | 68 - .../e2e/constants/CHROME_DRIVER_CONSTANTS.ts | 54 + tests/e2e/constants/ChromeDriverConstants.ts | 46 - tests/e2e/constants/FACTORY_TEST_CONSTANTS.ts | 61 + tests/e2e/constants/FactoryTestConstants.ts | 51 - tests/e2e/constants/MONACO_CONSTANTS.ts | 25 + tests/e2e/constants/MonacoConstants.ts | 22 - tests/e2e/constants/OAUTH_CONSTANTS.ts | 67 + tests/e2e/constants/OAuthConstants.ts | 57 - tests/e2e/constants/PLUGIN_TEST_CONSTANTS.ts | 15 + tests/e2e/constants/PluginsTestConstants.ts | 15 - tests/e2e/constants/REPORTER_CONSTANTS.ts | 53 + tests/e2e/constants/ReporterConstants.ts | 45 - tests/e2e/constants/TIMEOUT_CONSTANTS.ts | 131 + tests/e2e/constants/TimeoutConstants.ts | 113 - tests/e2e/driver/ChromeDriver.ts | 94 +- tests/e2e/driver/IDriver.ts | 6 +- tests/e2e/index.ts | 18 +- tests/e2e/package-lock.json | 8446 +++++++++++------ tests/e2e/package.json | 108 +- .../pageobjects/dashboard/CreateWorkspace.ts | 119 +- tests/e2e/pageobjects/dashboard/Dashboard.ts | 201 +- tests/e2e/pageobjects/dashboard/Workspaces.ts | 360 +- .../workspace-details/WorkspaceDetails.ts | 275 +- .../pageobjects/git-providers/OauthPage.ts | 343 +- .../pageobjects/ide/CheCodeLocatorLoader.ts | 95 +- .../login/interfaces/ICheLoginPage.ts | 6 +- .../login/interfaces/IOcpLoginPage.ts | 6 +- .../login/kubernetes/DexLoginPage.ts | 61 +- .../login/kubernetes/KubernetesLoginPage.ts | 29 +- .../login/openshift/OcpLoginPage.ts | 115 +- .../login/openshift/OcpRedHatLoginPage.ts | 53 +- .../login/openshift/OcpUserLoginPage.ts | 33 +- .../login/openshift/RedHatLoginPage.ts | 94 +- .../openshift/RegularUserOcpCheLoginPage.ts | 72 +- .../openshift/OcpApplicationPage.ts | 41 +- .../openshift/OcpImportFromGitPage.ts | 138 +- .../e2e/pageobjects/openshift/OcpMainPage.ts | 137 +- tests/e2e/specs/MochaHooks.ts | 109 +- tests/e2e/specs/SmokeTest.spec.ts | 83 +- .../specs/api/ContainerOverridesAPI.spec.ts | 59 +- .../api/DevfileAcceptanceTestAPI.spec.ts | 201 +- tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts | 119 +- tests/e2e/specs/api/PodOverridesAPI.spec.ts | 75 +- .../dashboard-samples/EmptyWorkspace.spec.ts | 62 +- .../specs/dashboard-samples/Quarkus.spec.ts | 68 +- .../RecommendedExtensions.spec.ts | 366 +- .../DevConsoleIntegration.spec.ts | 113 +- tests/e2e/specs/factory/Factory.spec.ts | 346 +- .../specs/factory/NoSetupRepoFactory.spec.ts | 437 +- .../specs/factory/RefusedOAuthFactory.spec.ts | 422 +- .../miscellaneous/PredefinedNamespace.spec.ts | 118 +- tests/e2e/tests-library/LoginTests.ts | 66 +- .../e2e/tests-library/ProjectAndFileTests.ts | 39 +- .../tests-library/WorkspaceHandlingTests.ts | 187 +- tests/e2e/tsconfig.json | 30 +- tests/e2e/tslint.json | 126 - tests/e2e/utils/BrowserTabsUtil.ts | 200 +- tests/e2e/utils/CheReporter.ts | 286 +- .../utils/DevWorkspaceConfigurationHelper.ts | 131 +- tests/e2e/utils/DevfilesRegistryHelper.ts | 125 +- tests/e2e/utils/DriverHelper.ts | 1426 +-- .../KubernetesCommandLineToolsExecutor.ts | 376 +- tests/e2e/utils/Logger.ts | 227 +- tests/e2e/utils/ScreenCatcher.ts | 103 +- tests/e2e/utils/ShellExecutor.ts | 30 +- tests/e2e/utils/StringUtil.ts | 72 +- .../request-handlers/CheApiRequestHandler.ts | 179 +- .../CheMultiuserAuthorizationHeaderHandler.ts | 53 +- .../headers/IAuthorizationHeaderHandler.ts | 6 +- tests/e2e/utils/workspace/ApiUrlResolver.ts | 57 +- .../e2e/utils/workspace/ITestWorkspaceUtil.ts | 62 +- .../e2e/utils/workspace/TestWorkspaceUtil.ts | 297 +- tests/e2e/utils/workspace/WorkspaceStatus.ts | 10 +- 86 files changed, 11046 insertions(+), 7933 deletions(-) create mode 100755 .husky/pre-commit create mode 100644 tests/e2e/.eslintignore create mode 100644 tests/e2e/.eslintrc.js create mode 100644 tests/e2e/.prettierignore create mode 100644 tests/e2e/.prettierrc.json delete mode 100644 tests/e2e/constants/APITestConstants.ts create mode 100644 tests/e2e/constants/API_TEST_CONSTANTS.ts create mode 100644 tests/e2e/constants/BASE_TEST_CONSTANTS.ts delete mode 100644 tests/e2e/constants/BaseTestConstants.ts create mode 100644 tests/e2e/constants/CHROME_DRIVER_CONSTANTS.ts delete mode 100644 tests/e2e/constants/ChromeDriverConstants.ts create mode 100644 tests/e2e/constants/FACTORY_TEST_CONSTANTS.ts delete mode 100644 tests/e2e/constants/FactoryTestConstants.ts create mode 100644 tests/e2e/constants/MONACO_CONSTANTS.ts delete mode 100644 tests/e2e/constants/MonacoConstants.ts create mode 100644 tests/e2e/constants/OAUTH_CONSTANTS.ts delete mode 100644 tests/e2e/constants/OAuthConstants.ts create mode 100644 tests/e2e/constants/PLUGIN_TEST_CONSTANTS.ts delete mode 100644 tests/e2e/constants/PluginsTestConstants.ts create mode 100644 tests/e2e/constants/REPORTER_CONSTANTS.ts delete mode 100644 tests/e2e/constants/ReporterConstants.ts create mode 100644 tests/e2e/constants/TIMEOUT_CONSTANTS.ts delete mode 100644 tests/e2e/constants/TimeoutConstants.ts delete mode 100644 tests/e2e/tslint.json diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000000..ea2476eb902 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +cd tests/e2e && npm run lint && npm run prettier diff --git a/tests/e2e/.eslintignore b/tests/e2e/.eslintignore new file mode 100644 index 00000000000..54b3feef68c --- /dev/null +++ b/tests/e2e/.eslintignore @@ -0,0 +1,10 @@ +build +**report +**results** +dist +node-modules +load** +resources +**/*.html +**/**/*.sh +index.ts diff --git a/tests/e2e/.eslintrc.js b/tests/e2e/.eslintrc.js new file mode 100644 index 00000000000..397a3321723 --- /dev/null +++ b/tests/e2e/.eslintrc.js @@ -0,0 +1,183 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +module.exports = { + env: { + browser: true, + es6: true, + node: true + }, + extends: ['plugin:@typescript-eslint/recommended-type-checked', 'prettier'], + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + sourceType: 'module' + }, + plugins: ['eslint-plugin-jsdoc', '@typescript-eslint', '@typescript-eslint/tslint', 'header', 'prettier'], + root: true, + rules: { + 'prettier/prettier': 'error', + '@typescript-eslint/dot-notation': 'error', + '@typescript-eslint/no-misused-promises': [ + 'error', + { + checksVoidReturn: { + arguments: false + } + } + ], + '@typescript-eslint/member-ordering': [ + 'error', + { + classes: ['field', 'constructor', 'method'] + } + ], + '@typescript-eslint/explicit-function-return-type': [ + 'error', + { + allowExpressions: false, + allowTypedFunctionExpressions: false, + allowHigherOrderFunctions: false, + allowDirectConstAssertionInArrowFunctions: true, + allowConciseArrowFunctionExpressionsStartingWithVoid: true + } + ], + '@typescript-eslint/explicit-module-boundary-types': [ + 'error', + { + allowArgumentsExplicitlyTypedAsAny: true, + allowDirectConstAssertionInArrowFunctions: true, + allowHigherOrderFunctions: false, + allowTypedFunctionExpressions: false + } + ], + '@typescript-eslint/member-delimiter-style': 'error', + '@typescript-eslint/naming-convention': [ + 'error', + { + selector: 'variable', + format: ['camelCase', 'UPPER_CASE'], + leadingUnderscore: 'forbid', + trailingUnderscore: 'forbid' + } + ], + '@typescript-eslint/no-empty-function': 'error', + '@typescript-eslint/no-parameter-properties': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-enum-comparison': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/restrict-plus-operands': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-unused-expressions': 'error', + '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/no-use-before-define': 'error', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/quotes': ['error', 'single'], + '@typescript-eslint/type-annotation-spacing': 'error', + '@typescript-eslint/typedef': [ + 'error', + { + parameter: true, + propertyDeclaration: true, + variableDeclaration: true, + memberVariableDeclaration: true + } + ], + 'brace-style': ['error', '1tbs'], + 'capitalized-comments': ['error', 'never'], + 'comma-dangle': ['error', 'never'], + curly: 'error', + 'dot-notation': 'off', + 'eol-last': 'error', + eqeqeq: ['error', 'smart'], + 'guard-for-in': 'error', + 'id-denylist': 'off', + 'id-match': 'off', + indent: 'off', + 'jsdoc/check-alignment': 'error', + 'jsdoc/check-indentation': 'error', + 'max-len': [ + 'off', + { + code: 140 + } + ], + 'no-bitwise': 'error', + 'no-caller': 'error', + 'no-console': [ + 'error', + { + allow: [ + 'log', + 'warn', + 'dir', + 'timeLog', + 'assert', + 'clear', + 'count', + 'countReset', + 'group', + 'groupEnd', + 'table', + 'dirxml', + 'error', + 'groupCollapsed', + 'Console', + 'profile', + 'profileEnd', + 'timeStamp', + 'context' + ] + } + ], + 'header/header': [ + 'error', + 'block', + [ + '* *******************************************************************', + { pattern: ' \\* copyright \\(c\\) [0-9-]{4,9} Red Hat, Inc\\.', template: '* copyright (c) 2023 Red Hat, Inc.' }, + ' *', + ' * This program and the accompanying materials are made', + ' * available under the terms of the Eclipse Public License 2.0', + ' * which is available at https://www.eclipse.org/legal/epl-2.0/', + ' *', + ' * SPDX-License-Identifier: EPL-2.0', + ' *********************************************************************' + ] + ], + 'no-debugger': 'error', + 'no-empty': 'error', + 'no-empty-function': 'off', + 'no-eval': 'error', + 'no-fallthrough': 'error', + 'no-new-wrappers': 'error', + 'no-redeclare': 'error', + 'no-trailing-spaces': 'error', + 'no-underscore-dangle': 'off', + 'no-unused-expressions': 'off', + 'no-unused-labels': 'error', + 'no-unused-vars': 'off', + 'no-use-before-define': 'off', + quotes: 'off', + radix: 'error', + semi: 'off', + 'spaced-comment': [ + 'error', + 'always', + { + markers: ['/'] + } + ] + } +}; diff --git a/tests/e2e/.prettierignore b/tests/e2e/.prettierignore new file mode 100644 index 00000000000..54b3feef68c --- /dev/null +++ b/tests/e2e/.prettierignore @@ -0,0 +1,10 @@ +build +**report +**results** +dist +node-modules +load** +resources +**/*.html +**/**/*.sh +index.ts diff --git a/tests/e2e/.prettierrc.json b/tests/e2e/.prettierrc.json new file mode 100644 index 00000000000..6e63cccf992 --- /dev/null +++ b/tests/e2e/.prettierrc.json @@ -0,0 +1,10 @@ +{ + "trailingComma": "none", + "tabWidth": 4, + "printWidth": 140, + "semi": true, + "singleQuote": true, + "useTabs": true, + "endOfLine": "lf", + "jsxSingleQuote": true +} diff --git a/tests/e2e/README.md b/tests/e2e/README.md index c2869d87cc5..d652889948d 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -1,87 +1,87 @@ - # Module for launch E2E tests related to Che 7 ## Requirements -- node 16.x -- "Chrome" browser 114.x or later -- deployed Che 7 with accessible URL +- node 16.x +- "Chrome" browser 114.x or later +- deployed Che 7 with accessible URL ## Before launch **Perform commands:** -- ```export TS_SELENIUM_BASE_URL=``` -- ```npm ci``` +- `export TS_SELENIUM_BASE_URL=` +- `npm ci` Note: If there is any modifications in package.json, manually execute the `npm install` to update the package-lock.json. So that errors can be avoided while executing npm ci ## Default launch -- Provide connection credentials: - - ```export TS_SELENIUM_OCP_USERNAME=``` - - ```export TS_SELENIUM_OCP_PASSWORD=``` - - ```npm run test``` +- Provide connection credentials: + - `export TS_SELENIUM_OCP_USERNAME=` + - `export TS_SELENIUM_OCP_PASSWORD=` + - `npm run test` ## Custom launch -- Use environment variables which described in the "constants" folder -- 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'``` -- To test one specification export file name as ```export USERSTORY= && npm run test``` (example: ```-e USERSTORY=Quarkus```) -- To run test without Selenium WebDriver (API tests etc.) use ```export USERSTORY= && npm run driver-less-test``` (example: ```-e USERSTORY=CloneGitRepoAPI```) -- This project support application testing deployed on Kubernetes or Openshift platform. Openshift is default value. To switch into Kubernetes, please, use `TS_PLATFORM=kubernetes` environmental variable and `TS_SELENIUM_K8S_PASSWORD`, `TS_SELENIUM_K8S_USERNAME` to provide credentials. The sample of test command in this case: - ``` - export TS_PLATFORM=kubernetes && \ - export TS_SELENIUM_K8S_USERNAME= && \ - export TS_SELENIUM_K8S_PASSWORD= && \ - export TS_SELENIUM_BASE_URL= && \ - npm run test - ``` - Also, environmental variables can be set in files in "constants" folder. - +- Use environment variables which described in the "constants" folder +- 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'` +- To test one specification export file name as `export USERSTORY= && npm run test` (example: `-e USERSTORY=Quarkus`) +- To run test without Selenium WebDriver (API tests etc.) use `export USERSTORY= && npm run driver-less-test` (example: `-e USERSTORY=CloneGitRepoAPI`) +- This project support application testing deployed on Kubernetes or Openshift platform. Openshift is default value. To switch into Kubernetes, please, use `TS_PLATFORM=kubernetes` environmental variable and `TS_SELENIUM_K8S_PASSWORD`, `TS_SELENIUM_K8S_USERNAME` to provide credentials. The sample of test command in this case: + ``` + export TS_PLATFORM=kubernetes && \ + export TS_SELENIUM_K8S_USERNAME= && \ + export TS_SELENIUM_K8S_PASSWORD= && \ + export TS_SELENIUM_BASE_URL= && \ + npm run test + ``` + Also, environmental variables can be set in files in "constants" folder. + ## Docker launch -- open terminal and go to the "e2e" directory -- export the ```"TS_SELENIUM_BASE_URL"``` variable with "Che" url -- run command ```"npm run test-docker"``` +- open terminal and go to the "e2e" directory +- export the `"TS_SELENIUM_BASE_URL"` variable with "Che" url +- run command `"npm run test-docker"` ## Docker launch with changed tests **For launching tests with local changes perform next steps:** -- open terminal and go to the "e2e" directory -- export the ```"TS_SELENIUM_BASE_URL"``` variable with "Che" url -- run command ```"npm run test-docker-mount-e2e"``` +- open terminal and go to the "e2e" directory +- export the `"TS_SELENIUM_BASE_URL"` variable with "Che" url +- run command `"npm run test-docker-mount-e2e"` ## Debug docker launch -The ```'eclipse/che-e2e'``` docker image has VNC server installed inside. For connecting use ```'0.0.0.0:5920'``` address. +The `'eclipse/che-e2e'` docker image has VNC server installed inside. For connecting use `'0.0.0.0:5920'` address. ## The "Happy Path" scenario launching **The easiest way to do that is to perform steps which are described in the "Docker launch" paragraph. For running tests without docker, please perform next steps:** -- Deploy Che on Kubernetes infrastructure by using 'Minikube' and 'Chectl' -- Create workspace by using 'Chectl' and devfile - - link to 'Chectl' manual - - link to devfile ( **```For successfull test passing, exactly provided devfile should be used```** ) - -- Provide the **```'TS_SELENIUM_BASE_URL'```** environment variable as described above -- export TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME=EmptyWorkspace (default value, see BaseTestConstants.ts) -- perform command **```export USERSTORY=$TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME && npm run test-all-devfiles```** +- Deploy Che on Kubernetes infrastructure by using 'Minikube' and 'Chectl' +- Create workspace by using 'Chectl' and devfile + - link to 'Chectl' manual + - link to devfile ( **`For successfull test passing, exactly provided devfile should be used`** ) + +- Provide the **`'TS_SELENIUM_BASE_URL'`** environment variable as described above +- export TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME=EmptyWorkspace (default value, see BASE_TEST_CONSTANTS.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 **Setup next environment variables:** -- export TS_SELENIUM_BASE_URL=\ -- export TS_SELENIUM_OCP_USERNAME=\ -- export TS_SELENIUM_OCP_PASSWORD=\ -- 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 BaseTestConstants.ts) +- export TS_SELENIUM_BASE_URL=\ +- export TS_SELENIUM_OCP_USERNAME=\ +- export TS_SELENIUM_OCP_PASSWORD=\ +- 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 BASE_TEST_CONSTANTS.ts) **Execute the npm command:** -- perform command ```export USERSTORY=$TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME && npm run test-all-devfiles``` + +- 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 f88ac8e44c3..00f6fc29ab8 100644 --- a/tests/e2e/configs/inversify.config.ts +++ b/tests/e2e/configs/inversify.config.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -42,8 +42,8 @@ import { OcpApplicationPage } from '../pageobjects/openshift/OcpApplicationPage' import { StringUtil } from '../utils/StringUtil'; import { KubernetesLoginPage } from '../pageobjects/login/kubernetes/KubernetesLoginPage'; import { DexLoginPage } from '../pageobjects/login/kubernetes/DexLoginPage'; -import { OAuthConstants } from '../constants/OAuthConstants'; -import { BaseTestConstants, Platform } from '../constants/BaseTestConstants'; +import { OAUTH_CONSTANTS } from '../constants/OAUTH_CONSTANTS'; +import { BASE_TEST_CONSTANTS, Platform } from '../constants/BASE_TEST_CONSTANTS'; const e2eContainer: Container = new Container({ defaultScope: 'Transient' }); @@ -73,10 +73,14 @@ e2eContainer.bind(CLASSES.ApiUrlResolver).to(ApiUrlResolver); e2eContainer.bind(CLASSES.WorkspaceHandlingTests).to(WorkspaceHandlingTests); e2eContainer.bind(CLASSES.RedHatLoginPage).to(RedHatLoginPage); -BaseTestConstants.TS_PLATFORM === Platform.OPENSHIFT ? - OAuthConstants.TS_SELENIUM_VALUE_OPENSHIFT_OAUTH ? - e2eContainer.bind(TYPES.CheLogin).to(RegularUserOcpCheLoginPage) : - e2eContainer.bind(TYPES.CheLogin).to(OcpRedHatLoginPage) : - e2eContainer.bind(TYPES.CheLogin).to(KubernetesLoginPage); +if (BASE_TEST_CONSTANTS.TS_PLATFORM === Platform.OPENSHIFT) { + if (OAUTH_CONSTANTS.TS_SELENIUM_VALUE_OPENSHIFT_OAUTH) { + e2eContainer.bind(TYPES.CheLogin).to(RegularUserOcpCheLoginPage); + } else { + e2eContainer.bind(TYPES.CheLogin).to(OcpRedHatLoginPage); + } +} else { + e2eContainer.bind(TYPES.CheLogin).to(KubernetesLoginPage); +} export { e2eContainer }; diff --git a/tests/e2e/configs/inversify.types.ts b/tests/e2e/configs/inversify.types.ts index 3c62c453165..97b03354d4e 100644 --- a/tests/e2e/configs/inversify.types.ts +++ b/tests/e2e/configs/inversify.types.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -9,36 +9,36 @@ **********************************************************************/ const TYPES: any = { - Driver: Symbol.for('Driver'), - CheLogin: Symbol.for('CheLogin'), - OcpLogin: Symbol.for('OcpLogin'), - WorkspaceUtil: Symbol.for('WorkspaceUtil'), - IAuthorizationHeaderHandler: Symbol.for('IAuthorizationHeaderHandler'), - ITokenHandler: Symbol.for('ITokenHandler') + Driver: Symbol.for('Driver'), + CheLogin: Symbol.for('CheLogin'), + OcpLogin: Symbol.for('OcpLogin'), + WorkspaceUtil: Symbol.for('WorkspaceUtil'), + IAuthorizationHeaderHandler: Symbol.for('IAuthorizationHeaderHandler'), + ITokenHandler: Symbol.for('ITokenHandler') }; const CLASSES: any = { - DriverHelper: 'DriverHelper', - Dashboard: 'Dashboard', - Workspaces: 'Workspaces', - WorkspaceDetails: 'WorkspaceDetails', - ScreenCatcher: 'ScreenCatcher', - OcpLoginPage: 'OcpLoginPage', - CheApiRequestHandler: 'CheApiRequestHandler', - CreateWorkspace: 'CreateWorkspace', - BrowserTabsUtil: 'BrowserTabsUtil', - ProjectAndFileTests: 'ProjectAndFileTests', - StringUtil: 'StringUtil', - ApiUrlResolver: 'ApiUrlResolver', - LoginTests: 'LoginTests', - WorkspaceHandlingTests: 'WorkspaceHandlingTests', - RedHatLoginPage: 'RedHatLoginPage', - KubernetesLoginPage: 'KubernetesLoginPage', - DexLoginPage: 'DexLoginPage', - OcpRedHatLoginPage: 'OcpRedHatLoginPage', - OcpApplicationPage: 'OcpApplicationPage', - OcpMainPage: 'OcpMainPage', - OcpImportFromGitPage: 'OcpImportFromGitPage' + DriverHelper: 'DriverHelper', + Dashboard: 'Dashboard', + Workspaces: 'Workspaces', + WorkspaceDetails: 'WorkspaceDetails', + ScreenCatcher: 'ScreenCatcher', + OcpLoginPage: 'OcpLoginPage', + CheApiRequestHandler: 'CheApiRequestHandler', + CreateWorkspace: 'CreateWorkspace', + BrowserTabsUtil: 'BrowserTabsUtil', + ProjectAndFileTests: 'ProjectAndFileTests', + StringUtil: 'StringUtil', + ApiUrlResolver: 'ApiUrlResolver', + LoginTests: 'LoginTests', + WorkspaceHandlingTests: 'WorkspaceHandlingTests', + RedHatLoginPage: 'RedHatLoginPage', + KubernetesLoginPage: 'KubernetesLoginPage', + DexLoginPage: 'DexLoginPage', + OcpRedHatLoginPage: 'OcpRedHatLoginPage', + OcpApplicationPage: 'OcpApplicationPage', + OcpMainPage: 'OcpMainPage', + OcpImportFromGitPage: 'OcpImportFromGitPage' }; export { TYPES, CLASSES }; diff --git a/tests/e2e/configs/mocharc.ts b/tests/e2e/configs/mocharc.ts index 7cf68f461a8..fd047fc3b25 100644 --- a/tests/e2e/configs/mocharc.ts +++ b/tests/e2e/configs/mocharc.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2020-2023 Red Hat, Inc. +/** ******************************************************************* + * copyright (c) 2020-2023 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -10,28 +10,25 @@ 'use strict'; -import { TimeoutConstants } from '../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; module.exports = { - timeout: 1200000, - reporter: 'dist/utils/CheReporter.js', - ui: 'tdd', - require: [ - 'dist/specs/MochaHooks.js', - 'ts-node/register', - ], - bail: true, - 'full-trace': true, - spec: - // variable MOCHA_DIRECTORY uses in command "test-all-devfiles" and sets up automatically. - // you can set it up to run files from specific directory with export environmental variable. - process.env.MOCHA_DIRECTORY ? - // to run one file (name without extension). uses in "test", "test-all-devfiles". - process.env.USERSTORY ? - `dist/specs/${process.env.MOCHA_DIRECTORY}/${process.env.USERSTORY}.spec.js` - : `dist/specs/${process.env.MOCHA_DIRECTORY}/**.spec.js` - : process.env.USERSTORY ? - [`dist/specs/**/${process.env.USERSTORY}.spec.js`, `dist/specs/${process.env.USERSTORY}.spec.js`] - : [`dist/specs/**/**.spec.js`, `dist/specs/**.spec.js`], - retries: TimeoutConstants.TS_SELENIUM_DEFAULT_ATTEMPTS + timeout: 1200000, + reporter: 'dist/utils/CheReporter.js', + ui: 'tdd', + require: ['dist/specs/MochaHooks.js', 'ts-node/register'], + bail: true, + 'full-trace': true, + spec: + // variable MOCHA_DIRECTORY uses in command "test-all-devfiles" and sets up automatically. + // you can set it up to run files from specific directory with export environmental variable. + process.env.MOCHA_DIRECTORY + ? // to run one file (name without extension). uses in "test", "test-all-devfiles". + process.env.USERSTORY + ? `dist/specs/${process.env.MOCHA_DIRECTORY}/${process.env.USERSTORY}.spec.js` + : `dist/specs/${process.env.MOCHA_DIRECTORY}/**.spec.js` + : process.env.USERSTORY + ? [`dist/specs/**/${process.env.USERSTORY}.spec.js`, `dist/specs/${process.env.USERSTORY}.spec.js`] + : ['dist/specs/**/**.spec.js', 'dist/specs/**.spec.js'], + retries: TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS }; diff --git a/tests/e2e/constants/APITestConstants.ts b/tests/e2e/constants/APITestConstants.ts deleted file mode 100644 index 5050e55fc00..00000000000 --- a/tests/e2e/constants/APITestConstants.ts +++ /dev/null @@ -1,57 +0,0 @@ -/********************************************************************* - * Copyright (c) 2020-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 { BaseTestConstants } from './BaseTestConstants'; - -export enum KubernetesCommandLineTool { - OC = 'oc', - KUBECTL = 'kubectl', -} - -export const SupportedDevfilesRegistries: any = { - INBUILT_APPLICATION_DEVFILE_REGISTRY_URL: () => `${BaseTestConstants.TS_SELENIUM_BASE_URL}/devfile-registry/devfiles/`, - GIT_HUB_CHE_DEVFILE_REGISTRY_URL: `https://api.github.com/repos/eclipse-che/che-devfile-registry/contents/devfiles/` -}; -export const APITestConstants: any = { - /** - * Possible values "oc" or "kubectl" - */ - TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL: process.env.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL || KubernetesCommandLineTool.OC, - - /** - * 'quay.io/devfile/universal-developer-image:latest' - * is default assigned by DevWorkspaceConfigurationHelper.generateDevfileContext() using @eclipse-che/che-devworkspace-generator - */ - TS_API_TEST_UDI_IMAGE: process.env.TS_API_TEST_UDI_IMAGE || undefined, - - /** - * https://eclipse-che.github.io/che-plugin-registry/main/v3/plugins/che-incubator/che-code/latest/devfile.yaml - * is default assigned by DevWorkspaceConfigurationHelper.generateDevfileContext() using @eclipse-che/che-devworkspace-generator - */ - TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI: process.env.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI || undefined, - - /** - * https://eclipse-che.github.io/che-plugin-registry/main/v3 - * is default assigned by DevWorkspaceConfigurationHelper.generateDevfileContext() using @eclipse-che/che-devworkspace-generator - */ - TS_API_TEST_PLUGIN_REGISTRY_URL: process.env.TS_API_TEST_PLUGIN_REGISTRY_URL || undefined, - - /** - * Namespace on openshift platform - */ - TS_API_TEST_NAMESPACE: process.env.TS_API_TEST_NAMESPACE || undefined, - - /** - * to run all devfile from registry. used in DevfileAcceptanceTestAPI.suite.ts - */ - TS_API_ACCEPTANCE_TEST_REGISTRY_URL(): string { - return process.env.TS_API_ACCEPTANCE_TEST_REGISTRY_URL || SupportedDevfilesRegistries.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL(); - } -}; diff --git a/tests/e2e/constants/API_TEST_CONSTANTS.ts b/tests/e2e/constants/API_TEST_CONSTANTS.ts new file mode 100644 index 00000000000..68279ffcb02 --- /dev/null +++ b/tests/e2e/constants/API_TEST_CONSTANTS.ts @@ -0,0 +1,67 @@ +/** ******************************************************************* + * copyright (c) 2020-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 { BASE_TEST_CONSTANTS } from './BASE_TEST_CONSTANTS'; + +export enum KubernetesCommandLineTool { + OC = 'oc', + KUBECTL = 'kubectl' +} + +export const SUPPORTED_DEVFILE_REGISTRIES: { + INBUILT_APPLICATION_DEVFILE_REGISTRY_URL: () => string; + GIT_HUB_CHE_DEVFILE_REGISTRY_URL: string; +} = { + INBUILT_APPLICATION_DEVFILE_REGISTRY_URL: (): string => `${BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL}/devfile-registry/devfiles/`, + GIT_HUB_CHE_DEVFILE_REGISTRY_URL: 'https://api.github.com/repos/eclipse-che/che-devfile-registry/contents/devfiles/' +}; +export const API_TEST_CONSTANTS: { + TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL: string; + TS_API_TEST_PLUGIN_REGISTRY_URL: string | undefined; + TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI: string | undefined; + TS_API_TEST_UDI_IMAGE: string | undefined; + TS_API_TEST_NAMESPACE: string | undefined; + TS_API_ACCEPTANCE_TEST_REGISTRY_URL(): string; +} = { + /** + * possible values "oc" or "kubectl" + */ + TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL: process.env.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL || KubernetesCommandLineTool.OC, + + /** + * 'quay.io/devfile/universal-developer-image:latest' + * is default assigned by DevWorkspaceConfigurationHelper.generateDevfileContext() using @eclipse-che/che-devworkspace-generator + */ + TS_API_TEST_UDI_IMAGE: process.env.TS_API_TEST_UDI_IMAGE || undefined, + + /** + * https://eclipse-che.github.io/che-plugin-registry/main/v3/plugins/che-incubator/che-code/latest/devfile.yaml + * is default assigned by DevWorkspaceConfigurationHelper.generateDevfileContext() using @eclipse-che/che-devworkspace-generator + */ + TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI: process.env.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI || undefined, + + /** + * https://eclipse-che.github.io/che-plugin-registry/main/v3 + * is default assigned by DevWorkspaceConfigurationHelper.generateDevfileContext() using @eclipse-che/che-devworkspace-generator + */ + TS_API_TEST_PLUGIN_REGISTRY_URL: process.env.TS_API_TEST_PLUGIN_REGISTRY_URL || undefined, + + /** + * namespace on openshift platform + */ + TS_API_TEST_NAMESPACE: process.env.TS_API_TEST_NAMESPACE || undefined, + + /** + * to run all devfile from registry. used in DevfileAcceptanceTestAPI.suite.ts + */ + TS_API_ACCEPTANCE_TEST_REGISTRY_URL(): string { + return process.env.TS_API_ACCEPTANCE_TEST_REGISTRY_URL || SUPPORTED_DEVFILE_REGISTRIES.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL(); + } +}; diff --git a/tests/e2e/constants/BASE_TEST_CONSTANTS.ts b/tests/e2e/constants/BASE_TEST_CONSTANTS.ts new file mode 100644 index 00000000000..6fb3f6a57eb --- /dev/null +++ b/tests/e2e/constants/BASE_TEST_CONSTANTS.ts @@ -0,0 +1,80 @@ +/** ******************************************************************* + * copyright (c) 2020-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 enum Platform { + OPENSHIFT = 'openshift', + KUBERNETES = 'kubernetes' +} + +export const BASE_TEST_CONSTANTS: { + TS_DEBUG_MODE: boolean; + TS_PLATFORM: string; + TS_SELENIUM_RESPONSE_INTERCEPTOR: boolean; + TS_SELENIUM_BASE_URL: string; + DELETE_WORKSPACE_ON_FAILED_TEST: boolean; + TS_SELENIUM_EDITOR: string; + TS_LOAD_TESTS: string; + TS_SELENIUM_REQUEST_INTERCEPTOR: boolean; + TS_SELENIUM_PROJECT_ROOT_FILE_NAME: string; + TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME: string; + IS_CLUSTER_DISCONNECTED: () => boolean; +} = { + /** + * base URL of the application which should be checked + */ + TS_SELENIUM_BASE_URL: !process.env.TS_SELENIUM_BASE_URL ? 'http://sample-url' : process.env.TS_SELENIUM_BASE_URL.replace(/\/$/, ''), + + IS_CLUSTER_DISCONNECTED: (): boolean => BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL.includes('airgap'), + + /** + * choose the platform where "che" application deployed, "openshift" by default. + */ + TS_PLATFORM: process.env.TS_PLATFORM || Platform.OPENSHIFT, + + /** + * editor the tests are running against, "code" by default. + * Possible values: "che-code" + */ + TS_SELENIUM_EDITOR: process.env.TS_SELENIUM_EDITOR || 'che-code', + + /** + * file name to check if project was imported + */ + TS_SELENIUM_PROJECT_ROOT_FILE_NAME: process.env.TS_SELENIUM_PROJECT_ROOT_FILE_NAME || 'devfile.yaml', + + /** + * name of workspace created for 'Happy Path' scenario validation. + */ + TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME: process.env.TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME || 'EmptyWorkspace', + + /** + * 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', + + /** + * enable Axios request interceptor, false by default + */ + TS_SELENIUM_REQUEST_INTERCEPTOR: process.env.TS_SELENIUM_REQUEST_INTERCEPTOR === 'true', + + /** + * enable Axios response interceptor, false by default + */ + TS_SELENIUM_RESPONSE_INTERCEPTOR: process.env.TS_SELENIUM_RESPONSE_INTERCEPTOR === 'true', + + /** + * stop and remove workspace if a test fails. + */ + DELETE_WORKSPACE_ON_FAILED_TEST: process.env.DELETE_WORKSPACE_ON_FAILED_TEST === 'true', + + /** + * constant, which prolong timeout constants for local debug. + */ + TS_DEBUG_MODE: process.env.TS_DEBUG_MODE === 'true' +}; diff --git a/tests/e2e/constants/BaseTestConstants.ts b/tests/e2e/constants/BaseTestConstants.ts deleted file mode 100644 index 0ff0fb2fb00..00000000000 --- a/tests/e2e/constants/BaseTestConstants.ts +++ /dev/null @@ -1,68 +0,0 @@ -/********************************************************************* - * Copyright (c) 2020-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 enum Platform { - OPENSHIFT = 'openshift', - KUBERNETES = 'kubernetes', -} - -export const BaseTestConstants: any = { - /** - * Base URL of the application which should be checked - */ - TS_SELENIUM_BASE_URL: !process.env.TS_SELENIUM_BASE_URL ? 'http://sample-url' : process.env.TS_SELENIUM_BASE_URL.replace(/\/$/, ''), - - IS_CLUSTER_DISCONNECTED: () => BaseTestConstants.TS_SELENIUM_BASE_URL.includes('airgap'), - - /** - * Choose the platform where "che" application deployed, "openshift" by default. - */ - TS_PLATFORM: process.env.TS_PLATFORM || Platform.OPENSHIFT, - - /** - * Editor the tests are running against, "code" by default. - * Possible values: "che-code" - */ - TS_SELENIUM_EDITOR: process.env.TS_SELENIUM_EDITOR || 'che-code', - - /** - * File name to check if project was imported - */ - TS_SELENIUM_PROJECT_ROOT_FILE_NAME: process.env.TS_SELENIUM_PROJECT_ROOT_FILE_NAME || 'devfile.yaml', - - /** - * Name of workspace created for 'Happy Path' scenario validation. - */ - TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME: process.env.TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME || 'EmptyWorkspace', - - /** - * 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', - - /** - * Enable Axios request interceptor, false by default - */ - TS_SELENIUM_REQUEST_INTERCEPTOR: process.env.TS_SELENIUM_REQUEST_INTERCEPTOR === 'true', - - /** - * Enable Axios response interceptor, false by default - */ - TS_SELENIUM_RESPONSE_INTERCEPTOR: process.env.TS_SELENIUM_RESPONSE_INTERCEPTOR === 'true', - - /** - * Stop and remove workspace if a test fails. - */ - DELETE_WORKSPACE_ON_FAILED_TEST: process.env.DELETE_WORKSPACE_ON_FAILED_TEST === 'true', - - /** - * Constant, which prolong timeout constants for local debug. - */ - TS_DEBUG_MODE: process.env.TS_DEBUG_MODE === 'true' -}; diff --git a/tests/e2e/constants/CHROME_DRIVER_CONSTANTS.ts b/tests/e2e/constants/CHROME_DRIVER_CONSTANTS.ts new file mode 100644 index 00000000000..99b7d1e522f --- /dev/null +++ b/tests/e2e/constants/CHROME_DRIVER_CONSTANTS.ts @@ -0,0 +1,54 @@ +/** ******************************************************************* + * copyright (c) 2020-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 const CHROME_DRIVER_CONSTANTS: { + TS_SELENIUM_RESOLUTION_WIDTH: number; + TS_SELENIUM_W3C_CHROME_OPTION: boolean; + TS_SELENIUM_HEADLESS: boolean; + TS_USE_WEB_DRIVER_FOR_TEST: boolean; + TS_SELENIUM_RESOLUTION_HEIGHT: number; + TS_SELENIUM_LAUNCH_FULLSCREEN: boolean; + TS_SELENIUM_REMOTE_DRIVER_URL: string; +} = { + /** + * remote driver URL. + */ + TS_SELENIUM_REMOTE_DRIVER_URL: process.env.TS_SELENIUM_REMOTE_DRIVER_URL || '', + + /** + * run browser in "Headless" (hidden) mode, "false" by default. + */ + TS_SELENIUM_HEADLESS: process.env.TS_SELENIUM_HEADLESS === 'true', + + /** + * create instance of chromedriver, "true" by default. Should be "false" to run only API tests. + */ + TS_USE_WEB_DRIVER_FOR_TEST: process.env.TS_USE_WEB_DRIVER_FOR_TEST !== 'false', + + /** + * run browser in "Fullscreen" (kiosk) mode. + * Default to true if undefined + */ + TS_SELENIUM_LAUNCH_FULLSCREEN: process.env.TS_SELENIUM_LAUNCH_FULLSCREEN !== 'false', + + /** + * run browser with an enabled or disabled W3C protocol (on Chrome 76 and upper, it is enabled by default), "true" by default. + */ + TS_SELENIUM_W3C_CHROME_OPTION: process.env.TS_SELENIUM_W3C_CHROME_OPTION !== 'false', + + /** + * browser width resolution, "1920" by default. + */ + TS_SELENIUM_RESOLUTION_WIDTH: Number(process.env.TS_SELENIUM_RESOLUTION_WIDTH) || 1920, + + /** + * browser height resolution, "1080" by default. + */ + TS_SELENIUM_RESOLUTION_HEIGHT: Number(process.env.TS_SELENIUM_RESOLUTION_HEIGHT) || 1080 +}; diff --git a/tests/e2e/constants/ChromeDriverConstants.ts b/tests/e2e/constants/ChromeDriverConstants.ts deleted file mode 100644 index 6bf7f3aa5dc..00000000000 --- a/tests/e2e/constants/ChromeDriverConstants.ts +++ /dev/null @@ -1,46 +0,0 @@ -/********************************************************************* - * Copyright (c) 2020-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 const ChromeDriverConstants: any = { - /** - * Remote driver URL. - */ - TS_SELENIUM_REMOTE_DRIVER_URL: process.env.TS_SELENIUM_REMOTE_DRIVER_URL || '', - - /** - * Run browser in "Headless" (hidden) mode, "false" by default. - */ - TS_SELENIUM_HEADLESS: process.env.TS_SELENIUM_HEADLESS === 'true', - - /** - * Create instance of chromedriver, "true" by default. Should be "false" to run only API tests. - */ - TS_USE_WEB_DRIVER_FOR_TEST: process.env.TS_USE_WEB_DRIVER_FOR_TEST !== 'false', - - /** - * Run browser in "Fullscreen" (kiosk) mode. - * Default to true if undefined - */ - TS_SELENIUM_LAUNCH_FULLSCREEN: (process.env.TS_SELENIUM_LAUNCH_FULLSCREEN !== 'false'), - - /** - * Run browser with an enabled or disabled W3C protocol (on Chrome 76 and upper, it is enabled by default), "true" by default. - */ - TS_SELENIUM_W3C_CHROME_OPTION: process.env.TS_SELENIUM_W3C_CHROME_OPTION !== 'false', - - /** - * Browser width resolution, "1920" by default. - */ - TS_SELENIUM_RESOLUTION_WIDTH: Number(process.env.TS_SELENIUM_RESOLUTION_WIDTH) || 1920, - - /** - * Browser height resolution, "1080" by default. - */ - TS_SELENIUM_RESOLUTION_HEIGHT: Number(process.env.TS_SELENIUM_RESOLUTION_HEIGHT) || 1080 -}; diff --git a/tests/e2e/constants/FACTORY_TEST_CONSTANTS.ts b/tests/e2e/constants/FACTORY_TEST_CONSTANTS.ts new file mode 100644 index 00000000000..9207062c5b4 --- /dev/null +++ b/tests/e2e/constants/FACTORY_TEST_CONSTANTS.ts @@ -0,0 +1,61 @@ +/** ******************************************************************* + * copyright (c) 2020-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 { BASE_TEST_CONSTANTS } from './BASE_TEST_CONSTANTS'; + +export enum GitProviderType { + GITHUB = 'github', + GITLAB = 'gitlab', + BITBUCKET = 'bitbucket', + AZURE_DEVOPS = 'azure-devops' +} + +export const FACTORY_TEST_CONSTANTS: { + TS_SELENIUM_FACTORY_GIT_REPO_URL: string; + TS_SELENIUM_PROJECT_NAME: string; + TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO: boolean; + TS_SELENIUM_FACTORY_GIT_PROVIDER: string; + TS_SELENIUM_FACTORY_GIT_REPO_BRANCH: string; + TS_SELENIUM_FACTORY_URL(): string; +} = { + /** + * git provider to check in factory tests + */ + TS_SELENIUM_FACTORY_GIT_PROVIDER: process.env.TS_SELENIUM_FACTORY_GIT_PROVIDER || GitProviderType.GITHUB, + + /** + * url to create factory + */ + TS_SELENIUM_FACTORY_GIT_REPO_URL: process.env.TS_SELENIUM_FACTORY_GIT_REPO_URL || '', + + /** + * git repository name + */ + TS_SELENIUM_PROJECT_NAME: process.env.TS_SELENIUM_PROJECT_NAME || '', + + /** + * is factory repository URL private or no + */ + TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO: process.env.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO === 'true', + + /** + * git repository main branch name (main or master) + */ + TS_SELENIUM_FACTORY_GIT_REPO_BRANCH: process.env.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH || 'master', + + /** + * full factory URL + */ + TS_SELENIUM_FACTORY_URL(): string { + return ( + process.env.TS_SELENIUM_FACTORY_URL || + BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL + '/dashboard/#/' + this.TS_SELENIUM_FACTORY_GIT_REPO_URL + ); + } +}; diff --git a/tests/e2e/constants/FactoryTestConstants.ts b/tests/e2e/constants/FactoryTestConstants.ts deleted file mode 100644 index cdb8be5d792..00000000000 --- a/tests/e2e/constants/FactoryTestConstants.ts +++ /dev/null @@ -1,51 +0,0 @@ -/********************************************************************* - * Copyright (c) 2020-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 { BaseTestConstants } from './BaseTestConstants'; - -export enum GitProviderType { - GITHUB = 'github', - GITLAB = 'gitlab', - BITBUCKET = 'bitbucket', - AZURE_DEVOPS = 'azure-devops' -} - -export const FactoryTestConstants: any = { - /** - * Git provider to check in factory tests - */ - TS_SELENIUM_FACTORY_GIT_PROVIDER: process.env.TS_SELENIUM_FACTORY_GIT_PROVIDER || GitProviderType.GITHUB, - - /** - * URL to create factory - */ - TS_SELENIUM_FACTORY_GIT_REPO_URL: process.env.TS_SELENIUM_FACTORY_GIT_REPO_URL || '', - - /** - * Git repository name - */ - TS_SELENIUM_PROJECT_NAME: process.env.TS_SELENIUM_PROJECT_NAME || '', - - /** - * Is factory repository URL private or no - */ - TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO: process.env.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO === 'true', - - /** - * Git repository main branch name (main or master) - */ - TS_SELENIUM_FACTORY_GIT_REPO_BRANCH: process.env.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH || 'master', - - /** - * Full factory URL - */ - TS_SELENIUM_FACTORY_URL(): string { - return process.env.TS_SELENIUM_FACTORY_URL || BaseTestConstants.TS_SELENIUM_BASE_URL + '/dashboard/#/' + this.TS_SELENIUM_FACTORY_GIT_REPO_URL; - } -}; diff --git a/tests/e2e/constants/MONACO_CONSTANTS.ts b/tests/e2e/constants/MONACO_CONSTANTS.ts new file mode 100644 index 00000000000..9e0cd41e52c --- /dev/null +++ b/tests/e2e/constants/MONACO_CONSTANTS.ts @@ -0,0 +1,25 @@ +/** ******************************************************************* + * copyright (c) 2020-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 const MONACO_CONSTANTS: { + TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION: string; + TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION: string; +} = { + /** + * base version of VSCode editor for monaco-page-objects, "1.37.0" by default. + */ + TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION: process.env.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION || '1.37.0', + + /** + * latest compatible version to be used, based on versions available in + * https://github.com/redhat-developer/vscode-extension-tester/tree/master/locators/lib , + * "1.73.0" by default. + */ + TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION: process.env.TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION || '1.73.0' +}; diff --git a/tests/e2e/constants/MonacoConstants.ts b/tests/e2e/constants/MonacoConstants.ts deleted file mode 100644 index d53c668f97a..00000000000 --- a/tests/e2e/constants/MonacoConstants.ts +++ /dev/null @@ -1,22 +0,0 @@ -/********************************************************************* - * Copyright (c) 2020-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 const MonacoConstants: any = { - /** - * Base version of VSCode editor for monaco-page-objects, "1.37.0" by default. - */ - TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION: process.env.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION || '1.37.0', - - /** - * Latest compatible version to be used, based on versions available in - * https://github.com/redhat-developer/vscode-extension-tester/tree/master/locators/lib , - * "1.73.0" by default. - */ - TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION: process.env.TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION || '1.73.0' -}; diff --git a/tests/e2e/constants/OAUTH_CONSTANTS.ts b/tests/e2e/constants/OAUTH_CONSTANTS.ts new file mode 100644 index 00000000000..c71b4ab8cab --- /dev/null +++ b/tests/e2e/constants/OAUTH_CONSTANTS.ts @@ -0,0 +1,67 @@ +/** ******************************************************************* + * copyright (c) 2020-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 const OAUTH_CONSTANTS: { + TS_SELENIUM_K8S_PASSWORD: string; + TS_SELENIUM_GIT_PROVIDER_PASSWORD: string; + TS_OCP_LOGIN_PAGE_PROVIDER_TITLE: string; + TS_SELENIUM_K8S_USERNAME: string; + TS_SELENIUM_GIT_PROVIDER_OAUTH: boolean; + TS_SELENIUM_OCP_USERNAME: string; + TS_SELENIUM_OCP_PASSWORD: string; + TS_SELENIUM_VALUE_OPENSHIFT_OAUTH: boolean; + TS_SELENIUM_GIT_PROVIDER_USERNAME: string; +} = { + /** + * value of OpenShift oAuth property determines how to login in installed application, + * if 'false' as an user of application, if 'true' as a regular user of OCP. + */ + TS_SELENIUM_VALUE_OPENSHIFT_OAUTH: process.env.TS_SELENIUM_VALUE_OPENSHIFT_OAUTH === 'true', + + /** + * log into OCP by using appropriate provider title. + */ + TS_OCP_LOGIN_PAGE_PROVIDER_TITLE: process.env.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE || '', + + /** + * regular username used to login in OCP. + */ + TS_SELENIUM_OCP_USERNAME: process.env.TS_SELENIUM_OCP_USERNAME || '', + + /** + * password regular user used to login in OCP. + */ + TS_SELENIUM_OCP_PASSWORD: process.env.TS_SELENIUM_OCP_PASSWORD || '', + + /** + * regular username used to login in Kubernetes. + */ + TS_SELENIUM_K8S_USERNAME: process.env.TS_SELENIUM_K8S_USERNAME || '', + + /** + * password regular user used to login in Kubernetes. + */ + TS_SELENIUM_K8S_PASSWORD: process.env.TS_SELENIUM_K8S_PASSWORD || '', + + /** + * for login via github for example on https://che-dogfooding.apps.che-dev.x6e0.p1.openshiftapps.com + * For factory tests + */ + TS_SELENIUM_GIT_PROVIDER_OAUTH: process.env.TS_SELENIUM_GIT_PROVIDER_OAUTH === 'true', + + /** + * git repository username + */ + TS_SELENIUM_GIT_PROVIDER_USERNAME: process.env.TS_SELENIUM_GIT_PROVIDER_USERNAME || '', + + /** + * git repository password + */ + TS_SELENIUM_GIT_PROVIDER_PASSWORD: process.env.TS_SELENIUM_GIT_PROVIDER_PASSWORD || '' +}; diff --git a/tests/e2e/constants/OAuthConstants.ts b/tests/e2e/constants/OAuthConstants.ts deleted file mode 100644 index 03b8227cfb0..00000000000 --- a/tests/e2e/constants/OAuthConstants.ts +++ /dev/null @@ -1,57 +0,0 @@ -/********************************************************************* - * Copyright (c) 2020-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 const OAuthConstants: any = { - /** - * Value of OpenShift oAuth property determines how to login in installed application, - * if 'false' as an user of application, if 'true' as a regular user of OCP. - */ - TS_SELENIUM_VALUE_OPENSHIFT_OAUTH: process.env.TS_SELENIUM_VALUE_OPENSHIFT_OAUTH === 'true', - - /** - * Log into OCP by using appropriate provider title. - */ - TS_OCP_LOGIN_PAGE_PROVIDER_TITLE: process.env.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE || '', - - /** - * Regular username used to login in OCP. - */ - TS_SELENIUM_OCP_USERNAME: process.env.TS_SELENIUM_OCP_USERNAME || '', - - /** - * Password regular user used to login in OCP. - */ - TS_SELENIUM_OCP_PASSWORD: process.env.TS_SELENIUM_OCP_PASSWORD || '', - - /** - * Regular username used to login in Kubernetes. - */ - TS_SELENIUM_K8S_USERNAME: process.env.TS_SELENIUM_K8S_USERNAME || '', - - /** - * Password regular user used to login in Kubernetes. - */ - TS_SELENIUM_K8S_PASSWORD: process.env.TS_SELENIUM_K8S_PASSWORD || '', - - /** - * For login via github for example on https://che-dogfooding.apps.che-dev.x6e0.p1.openshiftapps.com - * For factory tests - */ - TS_SELENIUM_GIT_PROVIDER_OAUTH: process.env.TS_SELENIUM_GIT_PROVIDER_OAUTH === 'true', - - /** - * Git repository username - */ - TS_SELENIUM_GIT_PROVIDER_USERNAME: process.env.TS_SELENIUM_GIT_PROVIDER_USERNAME || '', - - /** - * Git repository password - */ - TS_SELENIUM_GIT_PROVIDER_PASSWORD: process.env.TS_SELENIUM_GIT_PROVIDER_PASSWORD || '' -}; diff --git a/tests/e2e/constants/PLUGIN_TEST_CONSTANTS.ts b/tests/e2e/constants/PLUGIN_TEST_CONSTANTS.ts new file mode 100644 index 00000000000..d658746cfed --- /dev/null +++ b/tests/e2e/constants/PLUGIN_TEST_CONSTANTS.ts @@ -0,0 +1,15 @@ +/** ******************************************************************* + * copyright (c) 2020-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 const PLUGIN_TEST_CONSTANTS: { TS_SAMPLE_LIST: string } = { + /** + * dashboard samples to check in RecommendedExtensions.spec.ts + */ + TS_SAMPLE_LIST: process.env.TS_SAMPLE_LIST || 'Node.js MongoDB,Node.js Express' +}; diff --git a/tests/e2e/constants/PluginsTestConstants.ts b/tests/e2e/constants/PluginsTestConstants.ts deleted file mode 100644 index 769f8aafe53..00000000000 --- a/tests/e2e/constants/PluginsTestConstants.ts +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************* - * Copyright (c) 2020-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 const PluginsTestConstants: any = { - /** - * Dashboard samples to check in RecommendedExtensions.spec.ts - */ - TS_SAMPLE_LIST: process.env.TS_SAMPLE_LIST || 'Node.js MongoDB,Node.js Express', -}; diff --git a/tests/e2e/constants/REPORTER_CONSTANTS.ts b/tests/e2e/constants/REPORTER_CONSTANTS.ts new file mode 100644 index 00000000000..b9b566585a6 --- /dev/null +++ b/tests/e2e/constants/REPORTER_CONSTANTS.ts @@ -0,0 +1,53 @@ +/** ******************************************************************* + * copyright (c) 2020-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 const REPORTER_CONSTANTS: { + TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS: number; + TS_SELENIUM_REPORT_FOLDER: string; + TS_SELENIUM_EXECUTION_SCREENCAST: boolean; + TS_SELENIUM_PRINT_TIMEOUT_VARIABLES: string | boolean; + TS_SELENIUM_LOAD_TEST_REPORT_FOLDER: string; + TS_SELENIUM_LOG_LEVEL: string; + DELETE_SCREENCAST_IF_TEST_PASS: boolean; +} = { + /** + * path to folder with load tests execution report. + */ + TS_SELENIUM_LOAD_TEST_REPORT_FOLDER: process.env.TS_SELENIUM_LOAD_TEST_REPORT_FOLDER || './load-test-folder', + + /** + * delay between screenshots catching in the milliseconds for the execution screencast. + */ + TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS: Number(process.env.TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS) || 1000, + + /** + * path to folder with tests execution report. + */ + TS_SELENIUM_REPORT_FOLDER: process.env.TS_SELENIUM_REPORT_FOLDER || './report', + + /** + * enable or disable storing of execution screencast, "false" by default. + */ + TS_SELENIUM_EXECUTION_SCREENCAST: process.env.TS_SELENIUM_EXECUTION_SCREENCAST === 'true', + + /** + * delete screencast after execution if all tests passed, "true" by default. + */ + DELETE_SCREENCAST_IF_TEST_PASS: process.env.DELETE_SCREENCAST_IF_TEST_PASS !== 'false', + + /** + * log level settings, possible variants: 'INFO' (by default), 'DEBUG', 'TRACE'. + */ + TS_SELENIUM_LOG_LEVEL: process.env.TS_SELENIUM_LOG_LEVEL || 'INFO', + + /** + * print all timeout variables when tests launch, default to false + */ + TS_SELENIUM_PRINT_TIMEOUT_VARIABLES: process.env.TS_SELENIUM_PRINT_TIMEOUT_VARIABLES || false +}; diff --git a/tests/e2e/constants/ReporterConstants.ts b/tests/e2e/constants/ReporterConstants.ts deleted file mode 100644 index 1bea6d37a82..00000000000 --- a/tests/e2e/constants/ReporterConstants.ts +++ /dev/null @@ -1,45 +0,0 @@ -/********************************************************************* - * Copyright (c) 2020-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 const ReporterConstants: any = { - /** - * Path to folder with load tests execution report. - */ - TS_SELENIUM_LOAD_TEST_REPORT_FOLDER: process.env.TS_SELENIUM_LOAD_TEST_REPORT_FOLDER || './load-test-folder', - - /** - * Delay between screenshots catching in the milliseconds for the execution screencast. - */ - TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS: Number(process.env.TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS) || 1000, - - /** - * Path to folder with tests execution report. - */ - TS_SELENIUM_REPORT_FOLDER: process.env.TS_SELENIUM_REPORT_FOLDER || './report', - - /** - * Enable or disable storing of execution screencast, "false" by default. - */ - TS_SELENIUM_EXECUTION_SCREENCAST: process.env.TS_SELENIUM_EXECUTION_SCREENCAST === 'true', - - /** - * Delete screencast after execution if all tests passed, "true" by default. - */ - DELETE_SCREENCAST_IF_TEST_PASS: process.env.DELETE_SCREENCAST_IF_TEST_PASS !== 'false', - - /** - * Log level settings, possible variants: 'INFO' (by default), 'DEBUG', 'TRACE'. - */ - TS_SELENIUM_LOG_LEVEL: process.env.TS_SELENIUM_LOG_LEVEL || 'INFO', - - /** - * Print all timeout variables when tests launch, default to false - */ - TS_SELENIUM_PRINT_TIMEOUT_VARIABLES: process.env.TS_SELENIUM_PRINT_TIMEOUT_VARIABLES || false -}; diff --git a/tests/e2e/constants/TIMEOUT_CONSTANTS.ts b/tests/e2e/constants/TIMEOUT_CONSTANTS.ts new file mode 100644 index 00000000000..c72e39d8c0c --- /dev/null +++ b/tests/e2e/constants/TIMEOUT_CONSTANTS.ts @@ -0,0 +1,131 @@ +/** ******************************************************************* + * copyright (c) 2020-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 const TIMEOUT_CONSTANTS: { + TS_SELENIUM_WORKSPACE_STATUS_POLLING: number; + TS_COMMON_DASHBOARD_WAIT_TIMEOUT: number; + TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT: number; + TS_DIALOG_WINDOW_DEFAULT_TIMEOUT: number; + TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT: number; + TS_SELENIUM_CLICK_ON_VISIBLE_ITEM: number; + TS_SELENIUM_DEFAULT_ATTEMPTS: number; + TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS: number; + TS_SELENIUM_WAIT_FOR_URL: number; + TS_SELENIUM_DEFAULT_POLLING: number; + TS_IDE_LOAD_TIMEOUT: number; + TS_WAIT_LOADER_ABSENCE_TIMEOUT: number; + TS_WAIT_LOADER_PRESENCE_TIMEOUT: number; + TS_SELENIUM_START_WORKSPACE_TIMEOUT: number; + TS_SELENIUM_LOAD_PAGE_TIMEOUT: number; + TS_CLICK_DASHBOARD_ITEM_TIMEOUT: number; + TS_COMMON_PLUGIN_TEST_TIMEOUT: number; + TS_EDITOR_TAB_INTERACTION_TIMEOUT: number; +} = { + /** + * default amount of tries, "5" by default. + */ + TS_SELENIUM_DEFAULT_ATTEMPTS: Number(process.env.TS_SELENIUM_DEFAULT_ATTEMPTS) || 5, + + /** + * default delay in milliseconds between tries, "1000" by default. + */ + TS_SELENIUM_DEFAULT_POLLING: Number(process.env.TS_SELENIUM_DEFAULT_POLLING) || 1000, + + // -------------------------------------------- INSTALLING AND STARTUP -------------------------------------------- + + /** + * timeout waiting for url, "10 000" by default + */ + TS_SELENIUM_WAIT_FOR_URL: Number(process.env.TS_SELENIUM_WAIT_FOR_URL) || 10_000, + + /** + * amount of tries for checking workspace status. + */ + TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS: Number(process.env.TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS) || 90, + + /** + * delay in milliseconds between checking workspace status tries. + */ + TS_SELENIUM_WORKSPACE_STATUS_POLLING: Number(process.env.TS_SELENIUM_WORKSPACE_STATUS_POLLING) || 10000, + + /** + * wait between workspace started and IDE ready to be used, "20 000" by default. + */ + TS_IDE_LOAD_TIMEOUT: Number(process.env.TS_IDE_LOAD_TIMEOUT) || 20_000, + + /** + * timeout in milliseconds waiting for workspace start, "360 000" by default. + */ + TS_SELENIUM_START_WORKSPACE_TIMEOUT: Number(process.env.TS_SELENIUM_START_WORKSPACE_TIMEOUT) || 360_000, + + /** + * timeout in milliseconds waiting for page load, "20 000" by default. + */ + TS_SELENIUM_LOAD_PAGE_TIMEOUT: Number(process.env.TS_SELENIUM_LOAD_PAGE_TIMEOUT) || 20_000, + + /** + * wait for loader absence, "60 000" by default. + */ + TS_WAIT_LOADER_ABSENCE_TIMEOUT: Number(process.env.TS_WAIT_LOADER_ABSENCE_TIMEOUT) || 60_000, + + /** + * wait for loader absence, "60 000" by default. + */ + TS_WAIT_LOADER_PRESENCE_TIMEOUT: Number(process.env.TS_WAIT_LOADER_PRESENCE_TIMEOUT) || 60_000, + + // -------------------------------------------- DASHBOARD -------------------------------------------- + + /** + * common timeout for dashboard items, "5 000" by default + */ + TS_COMMON_DASHBOARD_WAIT_TIMEOUT: Number(process.env.TS_COMMON_DASHBOARD_WAIT_TIMEOUT) || 5_000, + + /** + * timeout for clicking on dashboard menu items, "2 000" by default + */ + TS_CLICK_DASHBOARD_ITEM_TIMEOUT: Number(process.env.TS_CLICK_DASHBOARD_ITEM_TIMEOUT) || 2_000, + + /** + * timeout for workspace stopped status, "30 000" by default + */ + TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT: Number(process.env.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT) || 30_000, + + // -------------------------------------------- PROJECT TREE -------------------------------------------- + + /** + * expand item in project tree, "8 000" by default. + */ + TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT: Number(process.env.TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT) || 8_000, + + // -------------------------------------------- EDITOR -------------------------------------------- + + /** + * timeout for inetractions with editor tab - wait, click, select, "8 000" by default. + */ + TS_EDITOR_TAB_INTERACTION_TIMEOUT: Number(process.env.TS_OPEN_PROJECT_TREE_TIMEOUT) || 8_000, + + // -------------------------------------------- IDE -------------------------------------------- + + /** + * timeout for context menu manipulation, "10 000" by default + */ + TS_DIALOG_WINDOW_DEFAULT_TIMEOUT: Number(process.env.TS_DIALOG_WINDOW_DEFAULT_TIMEOUT) || 10_000, + + /** + * timeout for clicking on visible item, "5 000" by default + */ + TS_SELENIUM_CLICK_ON_VISIBLE_ITEM: Number(process.env.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM) || 5_000, + + // ----------------------------------------- PLUGINS ----------------------------------------- + + /** + * common timeout for plugins. + */ + TS_COMMON_PLUGIN_TEST_TIMEOUT: Number(process.env.TS_COMMON_PLUGIN_TEST_TIMEOUT) || 30_000 +}; diff --git a/tests/e2e/constants/TimeoutConstants.ts b/tests/e2e/constants/TimeoutConstants.ts deleted file mode 100644 index d8524114ae7..00000000000 --- a/tests/e2e/constants/TimeoutConstants.ts +++ /dev/null @@ -1,113 +0,0 @@ -/********************************************************************* - * Copyright (c) 2020-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 const TimeoutConstants: any = { - /** - * Default amount of tries, "5" by default. - */ - TS_SELENIUM_DEFAULT_ATTEMPTS: Number(process.env.TS_SELENIUM_DEFAULT_ATTEMPTS) || 5, - - /** - * Default delay in milliseconds between tries, "1000" by default. - */ - TS_SELENIUM_DEFAULT_POLLING: Number(process.env.TS_SELENIUM_DEFAULT_POLLING) || 1000, - - // -------------------------------------------- INSTALLING AND STARTUP -------------------------------------------- - - /** - * Timeout waiting for url, "10 000" by default - */ - TS_SELENIUM_WAIT_FOR_URL: Number(process.env.TS_SELENIUM_WAIT_FOR_URL) || 10_000, - - /** - * Amount of tries for checking workspace status. - */ - TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS: Number(process.env.TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS) || 90, - - /** - * Delay in milliseconds between checking workspace status tries. - */ - TS_SELENIUM_WORKSPACE_STATUS_POLLING: Number(process.env.TS_SELENIUM_WORKSPACE_STATUS_POLLING) || 10000, - - /** - * Wait between workspace started and IDE ready to be used, "20 000" by default. - */ - TS_IDE_LOAD_TIMEOUT: Number(process.env.TS_IDE_LOAD_TIMEOUT) || 20_000, - - /** - * Timeout in milliseconds waiting for workspace start, "360 000" by default. - */ - TS_SELENIUM_START_WORKSPACE_TIMEOUT: Number(process.env.TS_SELENIUM_START_WORKSPACE_TIMEOUT) || 360_000, - - /** - * Timeout in milliseconds waiting for page load, "20 000" by default. - */ - TS_SELENIUM_LOAD_PAGE_TIMEOUT: Number(process.env.TS_SELENIUM_LOAD_PAGE_TIMEOUT) || 20_000, - - /** - * Wait for loader absence, "60 000" by default. - */ - TS_WAIT_LOADER_ABSENCE_TIMEOUT: Number(process.env.TS_WAIT_LOADER_ABSENCE_TIMEOUT) || 60_000, - - /** - * Wait for loader absence, "60 000" by default. - */ - TS_WAIT_LOADER_PRESENCE_TIMEOUT: Number(process.env.TS_WAIT_LOADER_PRESENCE_TIMEOUT) || 60_000, - - // -------------------------------------------- DASHBOARD -------------------------------------------- - - /** - * Common timeout for dashboard items, "5 000" by default - */ - TS_COMMON_DASHBOARD_WAIT_TIMEOUT: Number(process.env.TS_COMMON_DASHBOARD_WAIT_TIMEOUT) || 5_000, - - /** - * Timeout for clicking on dashboard menu items, "2 000" by default - */ - TS_CLICK_DASHBOARD_ITEM_TIMEOUT: Number(process.env.TS_CLICK_DASHBOARD_ITEM_TIMEOUT) || 2_000, - - /** - * Timeout for workspace stopped status, "30 000" by default - */ - TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT: Number(process.env.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT) || 30_000, - - // -------------------------------------------- PROJECT TREE -------------------------------------------- - - /** - * Expand item in project tree, "8 000" by default. - */ - TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT: Number(process.env.TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT) || 8_000, - - // -------------------------------------------- EDITOR -------------------------------------------- - - /** - * Timeout for inetractions with editor tab - wait, click, select, "8 000" by default. - */ - TS_EDITOR_TAB_INTERACTION_TIMEOUT: Number(process.env.TS_OPEN_PROJECT_TREE_TIMEOUT) || 8_000, - - // -------------------------------------------- IDE -------------------------------------------- - - /** - * Timeout for context menu manipulation, "10 000" by default - */ - TS_DIALOG_WINDOW_DEFAULT_TIMEOUT: Number(process.env.TS_DIALOG_WINDOW_DEFAULT_TIMEOUT) || 10_000, - - /** - * Timeout for clicking on visible item, "5 000" by default - */ - TS_SELENIUM_CLICK_ON_VISIBLE_ITEM: Number(process.env.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM) || 5_000, - - // ----------------------------------------- PLUGINS ----------------------------------------- - - /** - * Common timeout for plugins. - */ - TS_COMMON_PLUGIN_TEST_TIMEOUT: Number(process.env.TS_COMMON_PLUGIN_TEST_TIMEOUT) || 30_000 -}; diff --git a/tests/e2e/driver/ChromeDriver.ts b/tests/e2e/driver/ChromeDriver.ts index 52423b1b450..c1a0706ee80 100644 --- a/tests/e2e/driver/ChromeDriver.ts +++ b/tests/e2e/driver/ChromeDriver.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,63 +13,57 @@ import { injectable } from 'inversify'; import { Builder, ThenableWebDriver } from 'selenium-webdriver'; import { IDriver } from './IDriver'; import { Options } from 'selenium-webdriver/chrome'; -import { ChromeDriverConstants } from '../constants/ChromeDriverConstants'; +import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; @injectable() export class ChromeDriver implements IDriver { - private readonly driver: ThenableWebDriver | undefined; + private readonly driver: ThenableWebDriver | undefined; - constructor() { - const options: Options = this.getDriverOptions(); - if (ChromeDriverConstants.TS_USE_WEB_DRIVER_FOR_TEST) { - this.driver = this.getDriverBuilder(options).build(); - } - } + constructor() { + const options: Options = this.getDriverOptions(); + if (CHROME_DRIVER_CONSTANTS.TS_USE_WEB_DRIVER_FOR_TEST) { + this.driver = this.getDriverBuilder(options).build(); + } + } - get(): ThenableWebDriver { - return this.driver as ThenableWebDriver; - } + get(): ThenableWebDriver { + return this.driver as ThenableWebDriver; + } - async setWindowSize(): Promise { - await (this.driver as ThenableWebDriver) - .manage() - .window() - .setSize(ChromeDriverConstants.TS_SELENIUM_RESOLUTION_WIDTH, ChromeDriverConstants.TS_SELENIUM_RESOLUTION_HEIGHT); - } + async setWindowSize(): Promise { + await (this.driver as ThenableWebDriver) + .manage() + .window() + .setSize(CHROME_DRIVER_CONSTANTS.TS_SELENIUM_RESOLUTION_WIDTH, CHROME_DRIVER_CONSTANTS.TS_SELENIUM_RESOLUTION_HEIGHT); + } - private getDriverOptions(): Options { - let options: Options = new Options() - .addArguments('--no-sandbox') - .addArguments('--disable-web-security') - .addArguments('--allow-running-insecure-content') - .addArguments('--ignore-certificate-errors'); - // if 'true' run in 'headless' mode - if (ChromeDriverConstants.TS_SELENIUM_HEADLESS) { - options = options.addArguments('headless'); - } - return options; - } + private getDriverOptions(): Options { + let options: Options = new Options() + .addArguments('--no-sandbox') + .addArguments('--disable-web-security') + .addArguments('--allow-running-insecure-content') + .addArguments('--ignore-certificate-errors'); + // if 'true' run in 'headless' mode + if (CHROME_DRIVER_CONSTANTS.TS_SELENIUM_HEADLESS) { + options = options.addArguments('headless'); + } + return options; + } - private getDriverBuilder(options: Options): Builder { - const disableW3copts: object = { 'goog:chromeOptions': { 'w3c': false } }; - let builder: Builder = new Builder() - .forBrowser('chrome') - .setChromeOptions(options); + private getDriverBuilder(options: Options): Builder { + const disableW3copts: object = { 'goog:chromeOptions': { w3c: false } }; + let builder: Builder = new Builder().forBrowser('chrome').setChromeOptions(options); - // if 'false' w3c protocol is disabled - if (!ChromeDriverConstants.TS_SELENIUM_W3C_CHROME_OPTION) { - builder.withCapabilities(disableW3copts) - .forBrowser('chrome') - .setChromeOptions(options); - } + // if 'false' w3c protocol is disabled + if (!CHROME_DRIVER_CONSTANTS.TS_SELENIUM_W3C_CHROME_OPTION) { + builder.withCapabilities(disableW3copts).forBrowser('chrome').setChromeOptions(options); + } - // if 'true' run with remote driver - if (ChromeDriverConstants.TS_SELENIUM_REMOTE_DRIVER_URL) { - builder = builder.usingServer(ChromeDriverConstants.TS_SELENIUM_REMOTE_DRIVER_URL); - } - - return builder; - - } + // if 'true' run with remote driver + if (CHROME_DRIVER_CONSTANTS.TS_SELENIUM_REMOTE_DRIVER_URL) { + builder = builder.usingServer(CHROME_DRIVER_CONSTANTS.TS_SELENIUM_REMOTE_DRIVER_URL); + } + return builder; + } } diff --git a/tests/e2e/driver/IDriver.ts b/tests/e2e/driver/IDriver.ts index ed130dbad1b..70f66e7efb3 100644 --- a/tests/e2e/driver/IDriver.ts +++ b/tests/e2e/driver/IDriver.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -10,5 +10,5 @@ import { ThenableWebDriver } from 'selenium-webdriver'; export interface IDriver { - get(): ThenableWebDriver; + get(): ThenableWebDriver; } diff --git a/tests/e2e/index.ts b/tests/e2e/index.ts index b67dbe3b42a..552da32832b 100644 --- a/tests/e2e/index.ts +++ b/tests/e2e/index.ts @@ -41,12 +41,12 @@ export * from './pageobjects/openshift/OcpMainPage'; export * from './tests-library/LoginTests'; export * from './tests-library/ProjectAndFileTests'; export * from './tests-library/WorkspaceHandlingTests'; -export * from './constants/APITestConstants'; -export * from './constants/BaseTestConstants'; -export * from './constants/ChromeDriverConstants'; -export * from './constants/FactoryTestConstants'; -export * from './constants/MonacoConstants'; -export * from './constants/OAuthConstants'; -export * from './constants/PluginsTestConstants'; -export * from './constants/ReporterConstants'; -export * from './constants/TimeoutConstants'; +export * from './constants/API_TEST_CONSTANTS'; +export * from './constants/BASE_TEST_CONSTANTS'; +export * from './constants/CHROME_DRIVER_CONSTANTS'; +export * from './constants/FACTORY_TEST_CONSTANTS'; +export * from './constants/MONACO_CONSTANTS'; +export * from './constants/OAUTH_CONSTANTS'; +export * from './constants/PLUGIN_TEST_CONSTANTS'; +export * from './constants/REPORTER_CONSTANTS'; +export * from './constants/TIMEOUT_CONSTANTS'; diff --git a/tests/e2e/package-lock.json b/tests/e2e/package-lock.json index 63f6bfd40c0..603a15d5190 100644 --- a/tests/e2e/package-lock.json +++ b/tests/e2e/package-lock.json @@ -1,2920 +1,5530 @@ { - "name": "@eclipse-che/che-e2e", - "version": "7.74.0-SNAPSHOT", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.22.10", - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", - "dev": true - }, - "@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - } - }, - "@devfile/api": { - "version": "2.2.1-alpha-1667236163", - "resolved": "https://registry.npmjs.org/@devfile/api/-/api-2.2.1-alpha-1667236163.tgz", - "integrity": "sha512-tspoTrbyMbPIVwTD2qr6ljvQAJLE1lCN6uBFIGcYXKw89JGt0s0+WLQ/qIh2+RP5pDpDWbDp/yNFKCmzaOLupg==", - "dev": true, - "requires": { - "@types/bluebird": "3.5.21", - "@types/request": "*", - "bluebird": "^3.5.0", - "request": "^2.81.0", - "rewire": "^3.0.2" - } - }, - "@eclipse-che/api": { - "version": "7.72.0", - "resolved": "https://registry.npmjs.org/@eclipse-che/api/-/api-7.72.0.tgz", - "integrity": "sha512-baah1TSYAmCOuiFCHssb7mBoO5BrTAAz8tLV8Y1nqXvDIYMXXyHOnbBpl8/rVeplHGEZIDpFyFN1OGLoy6mcJA==" - }, - "@eclipse-che/che-devworkspace-generator": { - "version": "0.0.1-6ef61ae", - "resolved": "https://registry.npmjs.org/@eclipse-che/che-devworkspace-generator/-/che-devworkspace-generator-0.0.1-6ef61ae.tgz", - "integrity": "sha512-QTd4CVuqLjSeIDhP9lUZ3HT+yVKPZh5XbLk0dY4k0E6JEGhDoRk+CoLSa9RWGFATfI3VdlZWdgPkC7Wibnx5nQ==", - "dev": true, - "requires": { - "@devfile/api": "^2.2.1-alpha-1667236163", - "axios": "0.21.2", - "fs-extra": "^10.0.0", - "inversify": "^5.0.1", - "js-yaml": "^4.0.0", - "jsonc-parser": "^3.0.0", - "reflect-metadata": "^0.1.13" - }, - "dependencies": { - "axios": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.2.tgz", - "integrity": "sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==", - "dev": true, - "requires": { - "follow-redirects": "^1.14.0" - } - } - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@testim/chrome-version": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.3.tgz", - "integrity": "sha512-g697J3WxV/Zytemz8aTuKjTGYtta9+02kva3C1xc7KXB8GdbfE1akGJIsZLyY/FSh2QrnE+fiB7vmWU3XNcb6A==", - "dev": true - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "@types/bluebird": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.21.tgz", - "integrity": "sha512-6UNEwyw+6SGMC/WMI0ld0PS4st7Qq51qgguFrFizOSpGvZiqe9iswztFSdZvwJBEhLOy2JaxNE6VC7yMAlbfyQ==", - "dev": true - }, - "@types/caseless": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", - "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", - "dev": true - }, - "@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", - "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==", - "dev": true - }, - "@types/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", - "dev": true, - "requires": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, - "@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, - "@types/mocha": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", - "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", - "dev": true - }, - "@types/node": { - "version": "11.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.4.tgz", - "integrity": "sha512-+rabAZZ3Yn7tF/XPGHupKIL5EcAbrLxnTr/hgQICxbeuAfWtT0UZSfULE+ndusckBItcv4o6ZeOJplQikVcLvQ==", - "dev": true - }, - "@types/request": { - "version": "2.48.8", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.8.tgz", - "integrity": "sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ==", - "dev": true, - "requires": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" - } - }, - "@types/rimraf": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.2.tgz", - "integrity": "sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ==", - "dev": true, - "requires": { - "@types/glob": "*", - "@types/node": "*" - } - }, - "@types/selenium-webdriver": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-4.1.3.tgz", - "integrity": "sha512-wbLIzr+fG/JT2qGJUo4YU9oObkKI1TqNSxJZkQIlpK2xllJAAZA7+IcybSnC4537qGQEmhCHwWqFN1GC9r8dgw==", - "dev": true, - "requires": { - "@types/ws": "*" - } - }, - "@types/shelljs": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.12.tgz", - "integrity": "sha512-ZA8U81/gldY+rR5zl/7HSHrG2KDfEb3lzG6uCUDhW1DTQE9yC/VBQ45fXnXq8f3CgInfhZmjtdu/WOUlrXRQUg==", - "dev": true, - "requires": { - "@types/glob": "~7.2.0", - "@types/node": "*" - }, - "dependencies": { - "@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - } - } - }, - "@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", - "dev": true - }, - "@types/ws": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", - "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "dev": true, - "optional": true, - "requires": { - "@types/node": "*" - } - }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "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", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true - }, - "aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, - "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dev": true, - "requires": { - "follow-redirects": "^1.14.7" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "dev": true, - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ==", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha512-YiN6sFAQ5lML8JjCmr7uerS5Yc/EMbgg9G8ZNmk2E3nYX4ckHR01wrkeeMijEf5WHNK5TW0Sl0Uu3pv3EdOJWw==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A==", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", - "dev": true - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "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": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "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", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chromedriver": { - "version": "114.0.3", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-114.0.3.tgz", - "integrity": "sha512-Qy5kqsAUrCDwpovM5pIWFkb3X3IgJLoorigwFEDgC1boL094svny3N7yw06marJHAuyX4CE/hhd25RarIcKvKg==", - "dev": true, - "requires": { - "@testim/chrome-version": "^1.1.3", - "axios": "^1.4.0", - "compare-versions": "^6.0.0", - "extract-zip": "^2.0.1", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^1.1.0", - "tcp-port-used": "^1.0.1" - }, - "dependencies": { - "axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", - "dev": true, - "requires": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "clipboardy": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz", - "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", - "dev": true, - "requires": { - "arch": "^2.1.1", - "execa": "^1.0.0", - "is-wsl": "^2.1.1" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "compare-versions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", - "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "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", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true - }, - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "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", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg==", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "inversify": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz", - "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==" - }, - "ip-regex": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", - "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "is2": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.9.tgz", - "integrity": "sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "ip-regex": "^4.1.0", - "is-url": "^1.2.4" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==", - "dev": true - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", - "dev": true - }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dev": true, - "requires": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "requires": { - "immediate": "~3.0.5" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.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", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "4.2.1", - "ms": "2.1.3", - "nanoid": "3.3.1", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "monaco-page-objects": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/monaco-page-objects/-/monaco-page-objects-3.1.0.tgz", - "integrity": "sha512-B0ylDy9UcCeOkYHoWziimJDcBzgWPJHBrjYzKtBMjEw++Oo3eFJ00RN1XDjgzW6o7+wlG25M/atJ9010QfLoFw==", - "dev": true, - "requires": { - "clipboardy": "^2.3.0", - "clone-deep": "^4.0.1", - "compare-versions": "^3.5.1", - "fs-extra": "^10.0.0", - "ts-essentials": "^8.0.0" - }, - "dependencies": { - "compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", - "dev": true - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "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", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - } - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", - "dev": true, - "requires": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "rewire": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rewire/-/rewire-3.0.2.tgz", - "integrity": "sha512-ejkkt3qYnsQ38ifc9llAAzuHiGM7kR8N5/mL3aHWgmWwet0OMFcmJB8aTsMV2PBHCWxNVTLCeRfBpEa8X2+1fw==", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-plugin-transform-es2015-block-scoping": "^6.26.0" - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "selenium-webdriver": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.4.0.tgz", - "integrity": "sha512-Du+/xfpvNi9zHAeYgXhOWN9yH0hph+cuX+hHDBr7d+SbtQVcfNJwBzLsbdHrB1Wh7MHXFuIkSG88A9TRRQUx3g==", - "dev": true, - "requires": { - "jszip": "^3.10.0", - "tmp": "^0.2.1", - "ws": ">=8.7.0" - } - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true - }, - "shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "tcp-port-used": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz", - "integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==", - "dev": true, - "requires": { - "debug": "4.3.1", - "is2": "^2.0.6" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==", - "dev": true - }, - "ts-essentials": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-8.1.0.tgz", - "integrity": "sha512-34xALeQADWRYq9kbtprP4KdpTQ3v3BBIs/U4SpaP+C4++B8ijXY5NnILRJLchQVMzw7YBzKuGMUMrI9uT+ALVw==", - "dev": true - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "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", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", - "dev": true - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vscode-extension-tester-locators": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-extension-tester-locators/-/vscode-extension-tester-locators-3.1.0.tgz", - "integrity": "sha512-Q4gfJHnA1Kf6W0UOSE16jvPB+hk0aQ1r9b9bjM311r30hsdHkzBpAYw58YS8ZfzB7AgA4Jum/SM9q4WM2fwedg==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } + "name": "@eclipse-che/che-e2e", + "version": "7.73.0-SNAPSHOT", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@eclipse-che/che-e2e", + "version": "7.73.0-SNAPSHOT", + "license": "ISC", + "dependencies": { + "@eclipse-che/api": "latest", + "inversify": "5.0.1", + "reflect-metadata": "0.1.13" + }, + "devDependencies": { + "@eclipse-che/che-devworkspace-generator": "next", + "@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", + "@types/shelljs": "^0.8.11", + "@typescript-eslint/eslint-plugin": "^6.4.1", + "@typescript-eslint/eslint-plugin-tslint": "^6.1.0", + "@typescript-eslint/parser": "^6.1.0", + "axios": "^0.25.0", + "chai": "^4.3.4", + "chromedriver": "^114.0.2", + "clone-deep": "^4.0.1", + "eslint": "^8.45.0", + "eslint-config-prettier": "^8.10.0", + "eslint-plugin-header": "^3.1.1", + "eslint-plugin-jsdoc": "^46.5.0", + "eslint-plugin-prettier": "^5.0.0", + "husky": "^8.0.3", + "mocha": "^9.1.3", + "monaco-page-objects": "3.1.0", + "prettier": "^3.0.2", + "rimraf": "2.6.2", + "selenium-webdriver": "4.4.0", + "shelljs": "^0.8.5", + "ts-node": "^10.9.1", + "typescript": "3.9.9", + "vscode-extension-tester-locators": "3.1.0", + "yaml": "^2.2.2" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", + "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/highlight": "^7.22.10", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", + "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "peer": true + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@devfile/api": { + "version": "2.2.1-alpha-1667236163", + "resolved": "https://registry.npmjs.org/@devfile/api/-/api-2.2.1-alpha-1667236163.tgz", + "integrity": "sha512-tspoTrbyMbPIVwTD2qr6ljvQAJLE1lCN6uBFIGcYXKw89JGt0s0+WLQ/qIh2+RP5pDpDWbDp/yNFKCmzaOLupg==", + "dev": true, + "dependencies": { + "@types/bluebird": "3.5.21", + "@types/request": "*", + "bluebird": "^3.5.0", + "request": "^2.81.0", + "rewire": "^3.0.2" + } + }, + "node_modules/@eclipse-che/api": { + "version": "7.73.0", + "resolved": "https://registry.npmjs.org/@eclipse-che/api/-/api-7.73.0.tgz", + "integrity": "sha512-ydZPC5o7//UGu2D6spTxg5fpMcnqGeQpzhFtiHULKkuZ2xsw5eHiLEzYjBaeUDvSi/reQg7t72VqUD16+4Q2xg==" + }, + "node_modules/@eclipse-che/che-devworkspace-generator": { + "version": "0.0.1-6ef61ae", + "resolved": "https://registry.npmjs.org/@eclipse-che/che-devworkspace-generator/-/che-devworkspace-generator-0.0.1-6ef61ae.tgz", + "integrity": "sha512-QTd4CVuqLjSeIDhP9lUZ3HT+yVKPZh5XbLk0dY4k0E6JEGhDoRk+CoLSa9RWGFATfI3VdlZWdgPkC7Wibnx5nQ==", + "dev": true, + "dependencies": { + "@devfile/api": "latest", + "axios": "0.21.2", + "fs-extra": "^10.0.0", + "inversify": "^5.0.1", + "js-yaml": "^4.0.0", + "jsonc-parser": "^3.0.0", + "reflect-metadata": "^0.1.13" + }, + "bin": { + "che-devworkspace-generator": "lib/entrypoint.js" + } + }, + "node_modules/@eclipse-che/che-devworkspace-generator/node_modules/axios": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.2.tgz", + "integrity": "sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.40.1.tgz", + "integrity": "sha512-YORCdZSusAlBrFpZ77pJjc5r1bQs5caPWtAu+WWmiSo+8XaUzseapVrfAtiRFbQWnrBxxLLEwF6f6ZG/UgCQCg==", + "dev": true, + "dependencies": { + "comment-parser": "1.4.0", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", + "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@testim/chrome-version": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.3.tgz", + "integrity": "sha512-g697J3WxV/Zytemz8aTuKjTGYtta9+02kva3C1xc7KXB8GdbfE1akGJIsZLyY/FSh2QrnE+fiB7vmWU3XNcb6A==", + "dev": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/bluebird": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.21.tgz", + "integrity": "sha512-6UNEwyw+6SGMC/WMI0ld0PS4st7Qq51qgguFrFizOSpGvZiqe9iswztFSdZvwJBEhLOy2JaxNE6VC7yMAlbfyQ==", + "dev": true + }, + "node_modules/@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "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==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", + "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "11.13.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.4.tgz", + "integrity": "sha512-+rabAZZ3Yn7tF/XPGHupKIL5EcAbrLxnTr/hgQICxbeuAfWtT0UZSfULE+ndusckBItcv4o6ZeOJplQikVcLvQ==", + "dev": true + }, + "node_modules/@types/request": { + "version": "2.48.8", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.8.tgz", + "integrity": "sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ==", + "dev": true, + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "node_modules/@types/rimraf": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.2.tgz", + "integrity": "sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ==", + "dev": true, + "dependencies": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "node_modules/@types/selenium-webdriver": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-4.1.3.tgz", + "integrity": "sha512-wbLIzr+fG/JT2qGJUo4YU9oObkKI1TqNSxJZkQIlpK2xllJAAZA7+IcybSnC4537qGQEmhCHwWqFN1GC9r8dgw==", + "dev": true, + "dependencies": { + "@types/ws": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "node_modules/@types/shelljs": { + "version": "0.8.12", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.12.tgz", + "integrity": "sha512-ZA8U81/gldY+rR5zl/7HSHrG2KDfEb3lzG6uCUDhW1DTQE9yC/VBQ45fXnXq8f3CgInfhZmjtdu/WOUlrXRQUg==", + "dev": true, + "dependencies": { + "@types/glob": "~7.2.0", + "@types/node": "*" + } + }, + "node_modules/@types/shelljs/node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", + "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.1.tgz", + "integrity": "sha512-3F5PtBzUW0dYlq77Lcqo13fv+58KDwUib3BddilE8ajPJT+faGgxmI9Sw+I8ZS22BYwoir9ZhNXcLi+S+I2bkw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.4.1", + "@typescript-eslint/type-utils": "6.4.1", + "@typescript-eslint/utils": "6.4.1", + "@typescript-eslint/visitor-keys": "6.4.1", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin-tslint": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin-tslint/-/eslint-plugin-tslint-6.4.1.tgz", + "integrity": "sha512-Vxi7jQuQeJeY9d4eqbzs7trwAf/M9B8109tkzkxPg5tafg/EO0fS8+QS5e5JXyhkOwgWbtMmLHFZFQpk4RBGEw==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "6.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "tslint": "^5.0.0 || ^6.0.0", + "typescript": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ts-api-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", + "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.4.1.tgz", + "integrity": "sha512-610G6KHymg9V7EqOaNBMtD1GgpAmGROsmfHJPXNLCU9bfIuLrkdOygltK784F6Crboyd5tBFayPB7Sf0McrQwg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.4.1", + "@typescript-eslint/types": "6.4.1", + "@typescript-eslint/typescript-estree": "6.4.1", + "@typescript-eslint/visitor-keys": "6.4.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.4.1.tgz", + "integrity": "sha512-p/OavqOQfm4/Hdrr7kvacOSFjwQ2rrDVJRPxt/o0TOWdFnjJptnjnZ+sYDR7fi4OimvIuKp+2LCkc+rt9fIW+A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.4.1", + "@typescript-eslint/visitor-keys": "6.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.4.1.tgz", + "integrity": "sha512-7ON8M8NXh73SGZ5XvIqWHjgX2f+vvaOarNliGhjrJnv1vdjG0LVIz+ToYfPirOoBi56jxAKLfsLm40+RvxVVXA==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.4.1", + "@typescript-eslint/utils": "6.4.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ts-api-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", + "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.1.tgz", + "integrity": "sha512-zAAopbNuYu++ijY1GV2ylCsQsi3B8QvfPHVqhGdDcbx/NK5lkqMnCGU53amAjccSpk+LfeONxwzUhDzArSfZJg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.1.tgz", + "integrity": "sha512-xF6Y7SatVE/OyV93h1xGgfOkHr2iXuo8ip0gbfzaKeGGuKiAnzS+HtVhSPx8Www243bwlW8IF7X0/B62SzFftg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.4.1", + "@typescript-eslint/visitor-keys": "6.4.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ts-api-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", + "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.4.1.tgz", + "integrity": "sha512-F/6r2RieNeorU0zhqZNv89s9bDZSovv3bZQpUNOmmQK1L80/cV4KEu95YUJWi75u5PhboFoKUJBnZ4FQcoqhDw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.4.1", + "@typescript-eslint/types": "6.4.1", + "@typescript-eslint/typescript-estree": "6.4.1", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.1.tgz", + "integrity": "sha512-y/TyRJsbZPkJIZQXrHfdnxVnxyKegnpEvnRGNam7s3TRR2ykGefEWOhaef00/UUN3IZxizS7BTO3svd3lCOJRQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.4.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "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", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "node_modules/axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.7" + } + }, + "node_modules/babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "node_modules/babel-code-frame/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/babel-code-frame/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "dev": true, + "dependencies": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + } + }, + "node_modules/babel-core/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/babel-core/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/babel-core/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "dependencies": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + } + }, + "node_modules/babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ==", + "dev": true, + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "node_modules/babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", + "dev": true, + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha512-YiN6sFAQ5lML8JjCmr7uerS5Yc/EMbgg9G8ZNmk2E3nYX4ckHR01wrkeeMijEf5WHNK5TW0Sl0Uu3pv3EdOJWw==", + "dev": true, + "dependencies": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A==", + "dev": true, + "dependencies": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + } + }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dev": true, + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", + "dev": true, + "dependencies": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", + "dev": true, + "dependencies": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-traverse/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/babel-traverse/node_modules/globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-traverse/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", + "dev": true, + "dependencies": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "node_modules/babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true, + "bin": { + "babylon": "bin/babylon.js" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chai": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.8.tgz", + "integrity": "sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ==", + "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", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "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", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chromedriver": { + "version": "114.0.3", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-114.0.3.tgz", + "integrity": "sha512-Qy5kqsAUrCDwpovM5pIWFkb3X3IgJLoorigwFEDgC1boL094svny3N7yw06marJHAuyX4CE/hhd25RarIcKvKg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@testim/chrome-version": "^1.1.3", + "axios": "^1.4.0", + "compare-versions": "^6.0.0", + "extract-zip": "^2.0.1", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^1.1.0", + "tcp-port-used": "^1.0.1" + }, + "bin": { + "chromedriver": "bin/chromedriver" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/chromedriver/node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/chromedriver/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/clipboardy": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz", + "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", + "dev": true, + "dependencies": { + "arch": "^2.1.1", + "execa": "^1.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "peer": true + }, + "node_modules/comment-parser": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.0.tgz", + "integrity": "sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/compare-versions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-browser/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==", + "dev": true, + "dependencies": { + "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", + "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "^8.47.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-header": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz", + "integrity": "sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==", + "dev": true, + "peerDependencies": { + "eslint": ">=7.7.0" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.5.0.tgz", + "integrity": "sha512-aulXdA4I1dyWpzyS1Nh/GNoS6PavzeucxEapnMR4JUERowWvaEk2Y4A5irpHAcdXtBBHLVe8WIhdXNjoAlGQgA==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.40.1", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.0", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", + "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/inversify": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz", + "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==" + }, + "node_modules/ip-regex": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is2": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.9.tgz", + "integrity": "sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "ip-regex": "^4.1.0", + "is-url": "^1.2.4" + }, + "engines": { + "node": ">=v0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "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/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/monaco-page-objects": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/monaco-page-objects/-/monaco-page-objects-3.1.0.tgz", + "integrity": "sha512-B0ylDy9UcCeOkYHoWziimJDcBzgWPJHBrjYzKtBMjEw++Oo3eFJ00RN1XDjgzW6o7+wlG25M/atJ9010QfLoFw==", + "dev": true, + "dependencies": { + "clipboardy": "^2.3.0", + "clone-deep": "^4.0.1", + "compare-versions": "^3.5.1", + "fs-extra": "^10.0.0", + "ts-essentials": "^8.0.0" + }, + "peerDependencies": { + "selenium-webdriver": "^4.2.0" + } + }, + "node_modules/monaco-page-objects/node_modules/compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, + "node_modules/monaco-page-objects/node_modules/ts-essentials": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-8.1.0.tgz", + "integrity": "sha512-34xALeQADWRYq9kbtprP4KdpTQ3v3BBIs/U4SpaP+C4++B8ijXY5NnILRJLchQVMzw7YBzKuGMUMrI9uT+ALVw==", + "dev": true, + "peerDependencies": { + "typescript": ">=4.0.0" + } + }, + "node_modules/monaco-page-objects/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.2.tgz", + "integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "node_modules/repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==", + "dev": true, + "dependencies": { + "is-finite": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rewire": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rewire/-/rewire-3.0.2.tgz", + "integrity": "sha512-ejkkt3qYnsQ38ifc9llAAzuHiGM7kR8N5/mL3aHWgmWwet0OMFcmJB8aTsMV2PBHCWxNVTLCeRfBpEa8X2+1fw==", + "dev": true, + "dependencies": { + "babel-core": "^6.26.0", + "babel-plugin-transform-es2015-block-scoping": "^6.26.0" + } + }, + "node_modules/rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "dependencies": { + "glob": "^7.0.5" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-applescript/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-applescript/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/run-applescript/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/selenium-webdriver": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.4.0.tgz", + "integrity": "sha512-Du+/xfpvNi9zHAeYgXhOWN9yH0hph+cuX+hHDBr7d+SbtQVcfNJwBzLsbdHrB1Wh7MHXFuIkSG88A9TRRQUx3g==", + "dev": true, + "dependencies": { + "jszip": "^3.10.0", + "tmp": "^0.2.1", + "ws": ">=8.7.0" + }, + "engines": { + "node": ">= 10.15.0" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "peer": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tcp-port-used": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz", + "integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==", + "dev": true, + "dependencies": { + "debug": "4.3.1", + "is2": "^2.0.6" + } + }, + "node_modules/tcp-port-used/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/tmp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=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 || >= 3.2.0-dev || >= 4.0.0-dev" + } + }, + "node_modules/tslint/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/tslint/node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslint/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/tslint/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, + "node_modules/tslint/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslint/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/tslint/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "peer": true + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "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/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "peer": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", + "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/vscode-extension-tester-locators": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-extension-tester-locators/-/vscode-extension-tester-locators-3.1.0.tgz", + "integrity": "sha512-Q4gfJHnA1Kf6W0UOSE16jvPB+hk0aQ1r9b9bjM311r30hsdHkzBpAYw58YS8ZfzB7AgA4Jum/SM9q4WM2fwedg==", + "dev": true, + "peerDependencies": { + "monaco-page-objects": "^3.1.0", + "selenium-webdriver": "^4.2.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } } diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 9e0a450aefd..0ed7907c3ec 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -1,51 +1,61 @@ { - "name": "@eclipse-che/che-e2e", - "version": "7.74.0-SNAPSHOT", - "description": "", - "main": "dist/index.js", - "scripts": { - "lint": "tslint --fix -p .", - "tsc": "rm -rf ./dist && ./configs/sh-scripts/generateIndex.sh && tsc -p .", - "test": "./configs/sh-scripts/initDefaultValues.sh npm run lint && npm run tsc && export USERSTORY=$USERSTORY && mocha --config dist/configs/mocharc.js", - "driver-less-test": "export TS_USE_WEB_DRIVER_FOR_TEST=false && npm run test", - "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/initDefaultValues.sh && ./configs/sh-scripts/initDevfileTests.sh", - "devfile-acceptance-test-suite": "./configs/sh-scripts/initDefaultValues.sh npm run lint && npm run tsc && export TS_USE_WEB_DRIVER_FOR_TEST=false && mocha 'dist/specs/api/*.js' --config dist/configs/mocharc.js --delay --grep 'Devfile acceptance test suite'" - }, - "author": "Ihor Okhrimenko (iokhrime@redhat.com)", - "license": "ISC", - "devDependencies": { - "@eclipse-che/che-devworkspace-generator": "next", - "@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", - "@types/shelljs": "^0.8.11", - "axios": "^0.25.0", - "chai": "^4.3.4", - "chromedriver": "^114.0.2", - "clone-deep": "^4.0.1", - "mocha": "^9.1.3", - "monaco-page-objects": "3.1.0", - "rimraf": "2.6.2", - "selenium-webdriver": "4.4.0", - "shelljs": "^0.8.5", - "ts-node": "^10.9.1", - "tslint": "^6.1.3", - "typescript": "3.9.9", - "vscode-extension-tester-locators": "3.1.0", - "yaml": "^2.2.2" - }, - "dependencies": { - "@eclipse-che/api": "latest", - "inversify": "5.0.1", - "reflect-metadata": "0.1.13" - }, - "resolutions": { - "minimist": "^1.2.5" - } + "name": "@eclipse-che/che-e2e", + "version": "7.73.0-SNAPSHOT", + "description": "", + "main": "dist/index.js", + "scripts": { + "lint": "eslint --fix .", + "prettier": "prettier --config .prettierrc.json . --write", + "tsc": "rm -rf ./dist && ./configs/sh-scripts/generateIndex.sh && tsc -p .", + "test": "./configs/sh-scripts/initDefaultValues.sh npm run lint && npm run tsc && export USERSTORY=$USERSTORY && mocha --config dist/configs/mocharc.js", + "driver-less-test": "export TS_USE_WEB_DRIVER_FOR_TEST=false && npm run test", + "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/initDefaultValues.sh && ./configs/sh-scripts/initDevfileTests.sh", + "devfile-acceptance-test-suite": "./configs/sh-scripts/initDefaultValues.sh npm run lint && npm run tsc && export TS_USE_WEB_DRIVER_FOR_TEST=false && mocha 'dist/specs/api/*.js' --config dist/configs/mocharc.js --delay --grep 'Devfile acceptance test suite'" + }, + "author": "Ihor Okhrimenko (iokhrime@redhat.com)", + "license": "ISC", + "devDependencies": { + "@eclipse-che/che-devworkspace-generator": "next", + "@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", + "@types/shelljs": "^0.8.11", + "@typescript-eslint/eslint-plugin": "^6.4.1", + "@typescript-eslint/eslint-plugin-tslint": "^6.1.0", + "@typescript-eslint/parser": "^6.1.0", + "axios": "^0.25.0", + "chai": "^4.3.4", + "chromedriver": "^114.0.2", + "clone-deep": "^4.0.1", + "eslint": "^8.45.0", + "eslint-config-prettier": "^8.10.0", + "eslint-plugin-header": "^3.1.1", + "eslint-plugin-jsdoc": "^46.5.0", + "eslint-plugin-prettier": "^5.0.0", + "husky": "^8.0.3", + "mocha": "^9.1.3", + "monaco-page-objects": "3.1.0", + "prettier": "^3.0.2", + "rimraf": "2.6.2", + "selenium-webdriver": "4.4.0", + "shelljs": "^0.8.5", + "ts-node": "^10.9.1", + "typescript": "3.9.9", + "vscode-extension-tester-locators": "3.1.0", + "yaml": "^2.2.2" + }, + "dependencies": { + "@eclipse-che/api": "latest", + "inversify": "5.0.1", + "reflect-metadata": "0.1.13" + }, + "resolutions": { + "minimist": "^1.2.5" + } } diff --git a/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts b/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts index cf7b68778f6..45d4aa03e57 100644 --- a/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts +++ b/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,85 +13,94 @@ import { CLASSES } from '../../configs/inversify.types'; import { DriverHelper } from '../../utils/DriverHelper'; import { By, Key } from 'selenium-webdriver'; import { Logger } from '../../utils/Logger'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; @injectable() export class CreateWorkspace { - static readonly FACTORY_URL_LOCATOR: By = By.xpath(`//input[@id="git-repo-url"]`); + static readonly FACTORY_URL_LOCATOR: By = By.xpath('//input[@id="git-repo-url"]'); - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - async waitTitleContains(expectedText: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`text: "${expectedText}"`); + async waitTitleContains(expectedText: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(`text: "${expectedText}"`); - const pageTitleLocator: By = By.xpath(`//h1[contains(text(), '${expectedText}')]`); + const pageTitleLocator: By = By.xpath(`//h1[contains(text(), '${expectedText}')]`); - await this.driverHelper.waitVisibility(pageTitleLocator, timeout); - } + await this.driverHelper.waitVisibility(pageTitleLocator, timeout); + } - async waitPage(timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug(); + async waitPage(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); - await this.waitTitleContains('Create Workspace', timeout); - } + await this.waitTitleContains('Create Workspace', timeout); + } - async clickOnSampleNoEditorSelection(sampleName: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(`sampleName: "${sampleName}"`); + async clickOnSampleNoEditorSelection( + sampleName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + Logger.debug(`sampleName: "${sampleName}"`); - const sampleLocator: By = this.getSampleLocator(sampleName); + const sampleLocator: By = this.getSampleLocator(sampleName); - await this.driverHelper.waitAndClick(sampleLocator, timeout); - } + await this.driverHelper.waitAndClick(sampleLocator, timeout); + } - async clickOnSampleForSpecificEditor(sampleName: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - await this.clickOnEditorsDropdownListButton(sampleName, timeout); + async clickOnSampleForSpecificEditor( + sampleName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + await this.clickOnEditorsDropdownListButton(sampleName, timeout); - Logger.debug(`sampleName: "${sampleName}"`); + Logger.debug(`sampleName: "${sampleName}"`); - const sampleLocator: By = this.getSampleLocatorWithSpecificEditor(sampleName); - await this.driverHelper.waitAndClick(sampleLocator, timeout); - } + const sampleLocator: By = this.getSampleLocatorWithSpecificEditor(sampleName); + await this.driverHelper.waitAndClick(sampleLocator, timeout); + } - async importFromGitUsingUI(factoryUrl: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(`factoryUrl: "${factoryUrl}"`); - await this.driverHelper.waitVisibility(CreateWorkspace.FACTORY_URL_LOCATOR, timeout); - await this.driverHelper.type(CreateWorkspace.FACTORY_URL_LOCATOR, Key.chord(factoryUrl, Key.ENTER), timeout); - } + async importFromGitUsingUI(factoryUrl: string, timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(`factoryUrl: "${factoryUrl}"`); + await this.driverHelper.waitVisibility(CreateWorkspace.FACTORY_URL_LOCATOR, timeout); + await this.driverHelper.type(CreateWorkspace.FACTORY_URL_LOCATOR, Key.chord(factoryUrl, Key.ENTER), timeout); + } - private async clickOnEditorsDropdownListButton(sampleName: string, timeout: number): Promise { - Logger.debug(`sampleName: "${sampleName}, editor ${BaseTestConstants.TS_SELENIUM_EDITOR}"`); + private async clickOnEditorsDropdownListButton(sampleName: string, timeout: number): Promise { + Logger.debug(`sampleName: "${sampleName}, editor ${BASE_TEST_CONSTANTS.TS_SELENIUM_EDITOR}"`); - const editorDropdownListLocator: By = this.getEditorsDropdownListLocator(sampleName); - await this.driverHelper.waitAndClick(editorDropdownListLocator, timeout); - } + const editorDropdownListLocator: By = this.getEditorsDropdownListLocator(sampleName); + await this.driverHelper.waitAndClick(editorDropdownListLocator, timeout); + } - private getEditorsDropdownListLocator(sampleName: string): By { - return By.xpath(`//div[text()=\'${sampleName}\']//parent::article//button`); - } + private getEditorsDropdownListLocator(sampleName: string): By { + return By.xpath(`//div[text()=\'${sampleName}\']//parent::article//button`); + } - private getSampleLocatorWithSpecificEditor(sampleName: string): By { - let editor: string = ''; - switch (process.env.TS_SELENIUM_EDITOR) { - case 'che-code': - editor = 'code'; - break; - default: - throw new Error(`Unsupported editor ${process.env.TS_SELENIUM_EDITOR}`); - } + private getSampleLocatorWithSpecificEditor(sampleName: string): By { + let editor: string = ''; + switch (process.env.TS_SELENIUM_EDITOR) { + case 'che-code': + editor = 'code'; + break; + default: + throw new Error(`Unsupported editor ${process.env.TS_SELENIUM_EDITOR}`); + } - Logger.trace(`sampleName: ${sampleName}, editor "${editor}"`); + Logger.trace(`sampleName: ${sampleName}, editor "${editor}"`); - return By.xpath(`//div[text()='${sampleName}']//parent::article//span[text()[ + return By.xpath(`//div[text()='${sampleName}']//parent::article//span[text()[ contains( translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '${editor}')] ]//parent::a`); - } + } - private getSampleLocator(sampleName: string): By { - Logger.trace(`sampleName: ${sampleName}, used default editor`); + private getSampleLocator(sampleName: string): By { + Logger.trace(`sampleName: ${sampleName}, used default editor`); - return By.xpath(`//article[contains(@class, 'sample-card')]//div[text()='${sampleName}']`); - } + return By.xpath(`//article[contains(@class, 'sample-card')]//div[text()='${sampleName}']`); + } } diff --git a/tests/e2e/pageobjects/dashboard/Dashboard.ts b/tests/e2e/pageobjects/dashboard/Dashboard.ts index f3ef7ca2a3d..ea6cba3858c 100644 --- a/tests/e2e/pageobjects/dashboard/Dashboard.ts +++ b/tests/e2e/pageobjects/dashboard/Dashboard.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -12,107 +12,108 @@ import 'reflect-metadata'; import { CLASSES } from '../../configs/inversify.types'; import { By } from 'selenium-webdriver'; import { DriverHelper } from '../../utils/DriverHelper'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; import { Workspaces } from './Workspaces'; import { Logger } from '../../utils/Logger'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; @injectable() export class Dashboard { - private static readonly WORKSPACES_BUTTON: By = By.xpath(`//div[@id='page-sidebar']//a[contains(text(), 'Workspaces (')]`); - private static readonly CREATE_WORKSPACE_BUTTON: By = By.xpath(`//div[@id='page-sidebar']//a[text()='Create Workspace']`); - private static readonly LOADER_PAGE_STEP_TITLES: By = By.xpath('//*[@data-testid="step-title"]'); - private static readonly STARTING_PAGE_LOADER: By = By.css('.main-page-loader'); - private static readonly LOADER_ALERT: By = By.xpath('//*[@data-testid="loader-alert"]'); - private static readonly LOGOUT_BUTTON: By = By.xpath('//button[text()="Logout"]'); - private static readonly USER_SETTINGS_DROPDOWN: By = By.xpath('//header//button/span[text()!=\'\']//parent::button'); - - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, - @inject(CLASSES.Workspaces) private readonly workspaces: Workspaces) { - } - - async stopWorkspaceByUI(workspaceName: string): Promise { - Logger.debug(`"${workspaceName}"`); - - await this.clickWorkspacesButton(); - await this.workspaces.waitPage(); - await this.workspaces.waitWorkspaceListItem(workspaceName); - await this.workspaces.waitWorkspaceWithRunningStatus(workspaceName); - - await this.workspaces.stopWorkspaceByActionsButton(workspaceName); - await this.workspaces.waitWorkspaceWithStoppedStatus(workspaceName); - } - - async deleteStoppedWorkspaceByUI(workspaceName: string): Promise { - Logger.debug(`"${workspaceName}"`); - - await this.clickWorkspacesButton(); - await this.workspaces.waitPage(); - await this.workspaces.waitWorkspaceListItem(workspaceName); - await this.workspaces.deleteWorkspaceByActionsButton(workspaceName); - await this.workspaces.waitPage(); - await this.workspaces.waitWorkspaceListItemAbsence(workspaceName); - } - - async stopAndRemoveWorkspaceByUI(workspaceName: string): Promise { - Logger.debug(`"${workspaceName}"`); - - await this.stopWorkspaceByUI(workspaceName); - await this.workspaces.deleteWorkspaceByActionsButton(workspaceName); - await this.workspaces.waitWorkspaceListItemAbsence(workspaceName); - } - - async openDashboard(): Promise { - Logger.debug(); - await this.driverHelper.getDriver().navigate().to(BaseTestConstants.TS_SELENIUM_BASE_URL); - await this.waitPage(); - - } - - async waitPage(timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug(); - - await this.driverHelper.waitVisibility(Dashboard.WORKSPACES_BUTTON, timeout); - await this.driverHelper.waitVisibility(Dashboard.CREATE_WORKSPACE_BUTTON, timeout); - } - - async clickWorkspacesButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(); - - await this.driverHelper.waitAndClick(Dashboard.WORKSPACES_BUTTON, timeout); - } - - async clickCreateWorkspaceButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(); - - await this.driverHelper.waitAndClick(Dashboard.CREATE_WORKSPACE_BUTTON, timeout); - } - - async getLoaderAlert(timeout: number = TimeoutConstants.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { - Logger.debug(); - - return await this.driverHelper.waitAndGetText(Dashboard.LOADER_ALERT, timeout); - } - - async waitLoader(timeout: number = TimeoutConstants.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { - Logger.debug(); - - await this.driverHelper.waitAllPresence(Dashboard.LOADER_PAGE_STEP_TITLES, timeout); - } - - async waitStartingPageLoaderDisappearance(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(); - - await this.driverHelper.waitDisappearance(Dashboard.STARTING_PAGE_LOADER, timeout); - await this.driverHelper.wait(TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING); - } - - async logout(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(); - - await this.openDashboard(); - await this.driverHelper.waitAndClick(Dashboard.USER_SETTINGS_DROPDOWN, timeout); - await this.driverHelper.waitAndClick(Dashboard.LOGOUT_BUTTON, timeout); - await this.driverHelper.waitDisappearance(Dashboard.USER_SETTINGS_DROPDOWN, timeout); - } + private static readonly WORKSPACES_BUTTON: By = By.xpath('//div[@id="page-sidebar"]//a[contains(text(), "Workspaces (")]'); + private static readonly CREATE_WORKSPACE_BUTTON: By = By.xpath('//div[@id="page-sidebar"]//a[text()="Create Workspace"]'); + private static readonly LOADER_PAGE_STEP_TITLES: By = By.xpath('//*[@data-testid="step-title"]'); + private static readonly STARTING_PAGE_LOADER: By = By.css('.main-page-loader'); + private static readonly LOADER_ALERT: By = By.xpath('//*[@data-testid="loader-alert"]'); + private static readonly LOGOUT_BUTTON: By = By.xpath('//button[text()="Logout"]'); + private static readonly USER_SETTINGS_DROPDOWN: By = By.xpath('//header//button/span[text()!=""]//parent::button'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper, + @inject(CLASSES.Workspaces) private readonly workspaces: Workspaces + ) {} + + async stopWorkspaceByUI(workspaceName: string): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.clickWorkspacesButton(); + await this.workspaces.waitPage(); + await this.workspaces.waitWorkspaceListItem(workspaceName); + await this.workspaces.waitWorkspaceWithRunningStatus(workspaceName); + + await this.workspaces.stopWorkspaceByActionsButton(workspaceName); + await this.workspaces.waitWorkspaceWithStoppedStatus(workspaceName); + } + + async deleteStoppedWorkspaceByUI(workspaceName: string): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.clickWorkspacesButton(); + await this.workspaces.waitPage(); + await this.workspaces.waitWorkspaceListItem(workspaceName); + await this.workspaces.deleteWorkspaceByActionsButton(workspaceName); + await this.workspaces.waitPage(); + await this.workspaces.waitWorkspaceListItemAbsence(workspaceName); + } + + async stopAndRemoveWorkspaceByUI(workspaceName: string): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.stopWorkspaceByUI(workspaceName); + await this.workspaces.deleteWorkspaceByActionsButton(workspaceName); + await this.workspaces.waitWorkspaceListItemAbsence(workspaceName); + } + + async openDashboard(): Promise { + Logger.debug(); + await this.driverHelper.getDriver().navigate().to(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL); + await this.waitPage(); + } + + async waitPage(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(Dashboard.WORKSPACES_BUTTON, timeout); + await this.driverHelper.waitVisibility(Dashboard.CREATE_WORKSPACE_BUTTON, timeout); + } + + async clickWorkspacesButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(Dashboard.WORKSPACES_BUTTON, timeout); + } + + async clickCreateWorkspaceButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(Dashboard.CREATE_WORKSPACE_BUTTON, timeout); + } + + async getLoaderAlert(timeout: number = TIMEOUT_CONSTANTS.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { + Logger.debug(); + + return await this.driverHelper.waitAndGetText(Dashboard.LOADER_ALERT, timeout); + } + + async waitLoader(timeout: number = TIMEOUT_CONSTANTS.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAllPresence(Dashboard.LOADER_PAGE_STEP_TITLES, timeout); + } + + async waitStartingPageLoaderDisappearance(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitDisappearance(Dashboard.STARTING_PAGE_LOADER, timeout); + await this.driverHelper.wait(TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING); + } + + async logout(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + await this.openDashboard(); + await this.driverHelper.waitAndClick(Dashboard.USER_SETTINGS_DROPDOWN, timeout); + await this.driverHelper.waitAndClick(Dashboard.LOGOUT_BUTTON, timeout); + await this.driverHelper.waitDisappearance(Dashboard.USER_SETTINGS_DROPDOWN, timeout); + } } diff --git a/tests/e2e/pageobjects/dashboard/Workspaces.ts b/tests/e2e/pageobjects/dashboard/Workspaces.ts index 5ebbf58a43e..d099d6be940 100644 --- a/tests/e2e/pageobjects/dashboard/Workspaces.ts +++ b/tests/e2e/pageobjects/dashboard/Workspaces.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,202 +13,234 @@ import { DriverHelper } from '../../utils/DriverHelper'; import { CLASSES } from '../../configs/inversify.types'; import { By, WebElement } from 'selenium-webdriver'; import { Logger } from '../../utils/Logger'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; export enum WorkspaceStatusUI { - Running = 'green', - Stopped = 'grey' + Running = 'green', + Stopped = 'grey' } @injectable() export class Workspaces { - private static readonly ADD_WORKSPACE_BUTTON_XPATH: string = `//button[text()='Add Workspace']`; - private static readonly WORKSPACE_ITEM_TABLE_NAME_SECTION_XPATH: string = `//td[@data-label="Name"]/span/a`; + private static readonly ADD_WORKSPACE_BUTTON_XPATH: string = '//button[text()="Add Workspace"]'; + private static readonly WORKSPACE_ITEM_TABLE_NAME_SECTION_XPATH: string = '//td[@data-label="Name"]/span/a'; - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { - } + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - async waitPage(timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug(); + async waitPage(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); - await this.driverHelper.waitVisibility(By.xpath(Workspaces.ADD_WORKSPACE_BUTTON_XPATH), timeout); - } + await this.driverHelper.waitVisibility(By.xpath(Workspaces.ADD_WORKSPACE_BUTTON_XPATH), timeout); + } - async clickAddWorkspaceButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(); + async clickAddWorkspaceButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); - await this.driverHelper.waitAndClick(By.xpath(Workspaces.ADD_WORKSPACE_BUTTON_XPATH), timeout); - } + await this.driverHelper.waitAndClick(By.xpath(Workspaces.ADD_WORKSPACE_BUTTON_XPATH), timeout); + } - async clickOpenButton(workspaceName: string, timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug(); + async clickOpenButton(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); - await this.driverHelper.waitAndClick(this.getOpenButtonLocator(workspaceName), timeout); - } + await this.driverHelper.waitAndClick(this.getOpenButtonLocator(workspaceName), timeout); + } - async waitWorkspaceListItem(workspaceName: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`"${workspaceName}"`); + async waitWorkspaceListItem( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); - const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); + const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); - await this.driverHelper.waitVisibility(workspaceListItemLocator, timeout); - } + await this.driverHelper.waitVisibility(workspaceListItemLocator, timeout); + } - async waitWorkspaceWithRunningStatus(workspaceName: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`"${workspaceName}"`); + async waitWorkspaceWithRunningStatus( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); - const runningStatusLocator: By = this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Running); + const runningStatusLocator: By = this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Running); - await this.driverHelper.waitVisibility(runningStatusLocator, timeout); - } + await this.driverHelper.waitVisibility(runningStatusLocator, timeout); + } - async waitWorkspaceWithStoppedStatus(workspaceName: string, timeout: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug(`"${workspaceName}"`); + async waitWorkspaceWithStoppedStatus( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); - const stoppedStatusLocator: By = this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Stopped); + const stoppedStatusLocator: By = this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Stopped); - await this.driverHelper.waitVisibility(stoppedStatusLocator, timeout); - } + await this.driverHelper.waitVisibility(stoppedStatusLocator, timeout); + } - async clickWorkspaceListItem(workspaceName: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(`"${workspaceName}"`); + async clickWorkspaceListItem( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); - const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); + const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); - await this.driverHelper.waitAndClick(workspaceListItemLocator, timeout); - } + await this.driverHelper.waitAndClick(workspaceListItemLocator, timeout); + } - async clickActionsButton(workspaceName: string): Promise { - Logger.debug(`of the '${workspaceName}' list item`); + async clickActionsButton(workspaceName: string): Promise { + Logger.debug(`of the '${workspaceName}' list item`); - await this.driverHelper.waitAndClick(this.getActionsLocator(workspaceName)); - } + await this.driverHelper.waitAndClick(this.getActionsLocator(workspaceName)); + } - async waitActionsPopup(workspaceName: string, timeout: number = TimeoutConstants.TS_CONTEXT_MENU_TIMEOUT): Promise { - Logger.debug(`of the '${workspaceName}' list item`); + async waitActionsPopup(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(`of the '${workspaceName}' list item`); - await this.driverHelper.waitVisibility(this.getExpandedActionsLocator(workspaceName), timeout); - } + await this.driverHelper.waitVisibility(this.getExpandedActionsLocator(workspaceName), timeout); + } - async openActionsPopup(workspaceName: string, timeout: number = TimeoutConstants.TS_CONTEXT_MENU_TIMEOUT): Promise { - Logger.debug(`for the '${workspaceName}' list item`); - await this.clickActionsButton(workspaceName); - await this.waitActionsPopup(workspaceName, timeout); - } + async openActionsPopup(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(`for the '${workspaceName}' list item`); + await this.clickActionsButton(workspaceName); + await this.waitActionsPopup(workspaceName, timeout); + } - async clickActionsDeleteButton(workspaceName: string): Promise { - Logger.debug(`for the '${workspaceName}' list item`); + async clickActionsDeleteButton(workspaceName: string): Promise { + Logger.debug(`for the '${workspaceName}' list item`); - await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Delete Workspace')); - } + await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Delete Workspace')); + } - async clickActionsStopWorkspaceButton(workspaceName: string): Promise { - Logger.debug(`for the '${workspaceName}' list item`); - // todo: workaround because of issue CRW-3649 - try { - await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Stop Workspace')); - } catch (e) { - Logger.warn(`for the '${workspaceName}' list item - popup was missed, try to click one more time (issue CRW-3649).`); + async clickActionsStopWorkspaceButton(workspaceName: string): Promise { + Logger.debug(`for the '${workspaceName}' list item`); + // todo: workaround because of issue CRW-3649 + try { + await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Stop Workspace')); + } catch (e) { + Logger.warn(`for the '${workspaceName}' list item - popup was missed, try to click one more time (issue CRW-3649).`); - await this.driverHelper.waitAndClick(this.getActionsLocator(workspaceName)); - await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Stop Workspace')); - } - } + await this.driverHelper.waitAndClick(this.getActionsLocator(workspaceName)); + await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Stop Workspace')); + } + } - async waitDeleteWorkspaceConfirmationWindow(timeout: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug(); + async waitDeleteWorkspaceConfirmationWindow(timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { + Logger.debug(); - const confirmationWindowLocator: By = By.xpath(`//div[@aria-label='Delete workspaces confirmation window']`); - - await this.driverHelper.waitVisibility(confirmationWindowLocator, timeout); - } - - async clickToDeleteConfirmationCheckbox(timeout: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug(`Workspaces.clickToDeleteConfirmationCheckbox`); - - const deleteConfirmationCheckboxLocator: By = By.xpath(`//input[@data-testid='confirmation-checkbox']`); - - await this.driverHelper.waitAndClick(deleteConfirmationCheckboxLocator, timeout); - } - - async waitAndClickEnabledConfirmationWindowDeleteButton(timeout: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug(`Workspaces.waitEnabledConfirmationWindowDeleteButton`); - - const enabledConfirmationWindowDeleteButton: By = By.xpath(`//button[@data-testid='delete-workspace-button' and not(@disabled)]`); - - await this.driverHelper.waitAndClick(enabledConfirmationWindowDeleteButton, timeout); - } - - async deleteWorkspaceByActionsButton(workspaceName: string, timeout: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug('Workspaces.deleteWorkspaceByActionsButton'); - - await this.waitWorkspaceListItem(workspaceName, timeout); - await this.openActionsPopup(workspaceName, timeout); - await this.clickActionsDeleteButton(workspaceName); - await this.waitDeleteWorkspaceConfirmationWindow(timeout); - await this.clickToDeleteConfirmationCheckbox(timeout); - await this.waitAndClickEnabledConfirmationWindowDeleteButton(timeout); - } - - async stopWorkspaceByActionsButton(workspaceName: string, timeout: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug('Workspaces.stopWorkspaceByActionsButton'); - - await this.waitWorkspaceListItem(workspaceName, timeout); - await this.openActionsPopup(workspaceName, timeout); - await this.clickActionsStopWorkspaceButton(workspaceName); - } - - async waitWorkspaceListItemAbsence(workspaceName: string, timeout: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug(`Workspaces.waitWorkspaceListItemAbsence "${workspaceName}"`); - - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); - - await this.driverHelper.waitDisappearance(workspaceListItemLocator, attempts, polling); - } - - async getAllCreatedWorkspacesNames(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug('Workspaces.getAllCreatedWorkspacesNames'); - - const workspaceNames: string[] = []; - try { - const workspaceItems: WebElement[] = await this.driverHelper.waitAllPresence(By.xpath(Workspaces.WORKSPACE_ITEM_TABLE_NAME_SECTION_XPATH), timeout); - for (let item of workspaceItems) { - Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - try to get ${workspaceItems.indexOf(item)} items name`); - workspaceNames.push(await item.getText()); - Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - workspace name is "${workspaceNames[workspaceNames.length - 1]}"`); - } - } catch (e) { - Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - ${e}`); - } - - Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - ${workspaceNames.length} workspaces have been created in DevSpaces`); - return workspaceNames; - } - - private getWorkspaceListItemLocator(workspaceName: string): string { - return `//tr[td/span/a[text()='${workspaceName}']]`; - } - - private getWorkspaceStatusLocator(workspaceName: string, workspaceStatus: WorkspaceStatusUI): By { - return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//span[@data-testid='workspace-status-indicator']//*[local-name()='svg' and @fill='${workspaceStatus}']`); - } - - private getActionsLocator(workspaceName: string): By { - return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}/td/div/button[@aria-label='Actions']`); - } - - private getExpandedActionsLocator(workspaceName: string): By { - return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//button[@aria-label='Actions' and @aria-expanded='true']`); - } - - private getActionsPopupButtonLocator(workspaceName: string, buttonText: string): By { - return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//li[@role='menuitem']//button[text()='${buttonText}']`); - } - - private getOpenButtonLocator(workspaceName: string): By { - return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//td[@data-key=5]//a[text()='Open']`); - } + const confirmationWindowLocator: By = By.xpath('//div[@aria-label="Delete workspaces confirmation window"]'); + + await this.driverHelper.waitVisibility(confirmationWindowLocator, timeout); + } + + async clickToDeleteConfirmationCheckbox(timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { + Logger.debug('Workspaces.clickToDeleteConfirmationCheckbox'); + + const deleteConfirmationCheckboxLocator: By = By.xpath('//input[@data-testid="confirmation-checkbox"]'); + + await this.driverHelper.waitAndClick(deleteConfirmationCheckboxLocator, timeout); + } + + async waitAndClickEnabledConfirmationWindowDeleteButton( + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug('Workspaces.waitEnabledConfirmationWindowDeleteButton'); + + const enabledConfirmationWindowDeleteButton: By = By.xpath('//button[@data-testid="delete-workspace-button" and not(@disabled)]'); + + await this.driverHelper.waitAndClick(enabledConfirmationWindowDeleteButton, timeout); + } + + async deleteWorkspaceByActionsButton( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug('Workspaces.deleteWorkspaceByActionsButton'); + + await this.waitWorkspaceListItem(workspaceName, timeout); + await this.openActionsPopup(workspaceName, timeout); + await this.clickActionsDeleteButton(workspaceName); + await this.waitDeleteWorkspaceConfirmationWindow(timeout); + await this.clickToDeleteConfirmationCheckbox(timeout); + await this.waitAndClickEnabledConfirmationWindowDeleteButton(timeout); + } + + async stopWorkspaceByActionsButton( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug('Workspaces.stopWorkspaceByActionsButton'); + + await this.waitWorkspaceListItem(workspaceName, timeout); + await this.openActionsPopup(workspaceName, timeout); + await this.clickActionsStopWorkspaceButton(workspaceName); + } + + async waitWorkspaceListItemAbsence( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug(`Workspaces.waitWorkspaceListItemAbsence "${workspaceName}"`); + + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); + + await this.driverHelper.waitDisappearance(workspaceListItemLocator, attempts, polling); + } + + async getAllCreatedWorkspacesNames(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug('Workspaces.getAllCreatedWorkspacesNames'); + + const workspaceNames: string[] = []; + try { + const workspaceItems: WebElement[] = await this.driverHelper.waitAllPresence( + By.xpath(Workspaces.WORKSPACE_ITEM_TABLE_NAME_SECTION_XPATH), + timeout + ); + for (const item of workspaceItems) { + Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - try to get ${workspaceItems.indexOf(item)} items name`); + workspaceNames.push(await item.getText()); + Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - workspace name is "${workspaceNames[workspaceNames.length - 1]}"`); + } + } catch (e) { + Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - ${e}`); + } + + Logger.debug(`Workspaces.getAllCreatedWorkspacesNames - ${workspaceNames.length} workspaces have been created in DevSpaces`); + return workspaceNames; + } + + private getWorkspaceListItemLocator(workspaceName: string): string { + return `//tr[td/span/a[text()='${workspaceName}']]`; + } + + private getWorkspaceStatusLocator(workspaceName: string, workspaceStatus: WorkspaceStatusUI): By { + return By.xpath( + `${this.getWorkspaceListItemLocator( + workspaceName + )}//span[@data-testid='workspace-status-indicator']//*[local-name()='svg' and @fill='${workspaceStatus}']` + ); + } + + private getActionsLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}/td/div/button[@aria-label='Actions']`); + } + + private getExpandedActionsLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//button[@aria-label='Actions' and @aria-expanded='true']`); + } + + private getActionsPopupButtonLocator(workspaceName: string, buttonText: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//li[@role='menuitem']//button[text()='${buttonText}']`); + } + + private getOpenButtonLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//td[@data-key=5]//a[text()='Open']`); + } } diff --git a/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts b/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts index 529736ba1f6..d74cc0f7624 100644 --- a/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts +++ b/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -14,138 +14,163 @@ import 'reflect-metadata'; import { By } from 'selenium-webdriver'; import { WorkspaceStatus } from '../../../utils/workspace/WorkspaceStatus'; import { Logger } from '../../../utils/Logger'; -import { TimeoutConstants } from '../../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; import { ITestWorkspaceUtil } from '../../../utils/workspace/ITestWorkspaceUtil'; import { ProjectAndFileTests } from '../../../tests-library/ProjectAndFileTests'; @injectable() export class WorkspaceDetails { - private static readonly RUN_BUTTON_CSS: string = '#run-workspace-button[che-button-title=\'Run\']'; - private static readonly OPEN_BUTTON_CSS: string = '#open-in-ide-button[che-button-title=\'Open\']'; - private static readonly SAVE_BUTTON_CSS: string = 'button[name=\'save-button\']'; - private static readonly ENABLED_SAVE_BUTTON_CSS: string = 'button[name=\'save-button\'][aria-disabled=\'false\']'; - private static readonly WORKSPACE_DETAILS_LOADER_CSS: string = 'workspace-details-overview md-progress-linear'; + private static readonly RUN_BUTTON_CSS: string = '#run-workspace-button[che-button-title="Run"]'; + private static readonly OPEN_BUTTON_CSS: string = '#open-in-ide-button[che-button-title="Open"]'; + private static readonly SAVE_BUTTON_CSS: string = 'button[name="save-button"]'; + private static readonly ENABLED_SAVE_BUTTON_CSS: string = 'button[name="save-button"][aria-disabled="false"]'; + private static readonly WORKSPACE_DETAILS_LOADER_CSS: string = 'workspace-details-overview md-progress-linear'; + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper, + @inject(TYPES.WorkspaceUtil) + private readonly testWorkspaceUtil: ITestWorkspaceUtil, + @inject(CLASSES.ProjectAndFileTests) + private readonly testProjectAndFileCheCode: ProjectAndFileTests + ) {} + + async waitLoaderDisappearance( + attempts: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, + polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING + ): Promise { + Logger.debug(); + + await this.driverHelper.waitDisappearance(By.css(WorkspaceDetails.WORKSPACE_DETAILS_LOADER_CSS), attempts, polling); + } + + async saveChanges(): Promise { + Logger.debug(); + + await this.waitSaveButton(); + await this.clickOnSaveButton(); + await this.waitSaveButtonDisappearance(); + } + + async waitPage(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(`workspace: "${workspaceName}"`); + + await this.waitWorkspaceTitle(workspaceName, timeout); + await this.waitOpenButton(timeout); + await this.waitRunButton(timeout); + await this.waitTabsPresence(timeout); + await this.waitLoaderDisappearance(timeout); + } + + async waitWorkspaceTitle(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(`title: "${workspaceName}"`); + + const workspaceTitleLocator: By = By.css(this.getWorkspaceTitleCssLocator(workspaceName)); + + await this.driverHelper.waitVisibility(workspaceTitleLocator, timeout); + } + + async waitRunButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.RUN_BUTTON_CSS), timeout); + } + + async clickOnRunButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.RUN_BUTTON_CSS), timeout); + } + + async waitOpenButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.OPEN_BUTTON_CSS), timeout); + } + + async openWorkspace( + namespace: string, + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT + ): Promise { + Logger.debug(`"${namespace}/${workspaceName}"`); + + await this.clickOnOpenButton(timeout); + await this.testProjectAndFileCheCode.waitWorkspaceReadinessForCheCodeEditor(); + // await + this.testWorkspaceUtil.waitWorkspaceStatus(namespace, workspaceName, WorkspaceStatus.STARTING); + } + + async waitTabsPresence(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug('WorkspaceDetails.waitTabsPresence'); + + const workspaceDetailsTabs: Array = [ + 'Overview', + 'Projects', + 'Containers', + 'Servers', + 'Env Variables', + 'Volumes', + 'Config', + 'SSH', + 'Plugins', + 'Editors' + ]; + + for (const tabTitle of workspaceDetailsTabs) { + const workspaceDetailsTabLocator: By = By.xpath(this.getTabXpathLocator(tabTitle)); + + await this.driverHelper.waitVisibility(workspaceDetailsTabLocator, timeout); + } + } + + async selectTab(tabTitle: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(`WorkspaceDetails.selectTab ${tabTitle}`); + + await this.clickOnTab(tabTitle, timeout); + await this.waitTabSelected(tabTitle, timeout); + } + + private getWorkspaceTitleCssLocator(workspaceName: string): string { + return `che-row-toolbar[che-title='${workspaceName}']`; + } - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, - @inject(TYPES.WorkspaceUtil) private readonly testWorkspaceUtil: ITestWorkspaceUtil, - @inject(CLASSES.ProjectAndFileTests) private readonly testProjectAndFileCheCode: ProjectAndFileTests) { } + private getTabXpathLocator(tabTitle: string): string { + return `//md-tabs-canvas//md-tab-item//span[text()='${tabTitle}']`; + } - async waitLoaderDisappearance(attempts: number = TimeoutConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING): Promise { - Logger.debug(); + private getSelectedTabXpathLocator(tabTitle: string): string { + return `//md-tabs-canvas[@role='tablist']//md-tab-item[@aria-selected='true']//span[text()='${tabTitle}']`; + } - await this.driverHelper.waitDisappearance(By.css(WorkspaceDetails.WORKSPACE_DETAILS_LOADER_CSS), attempts, polling); - } + private async waitSaveButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.ENABLED_SAVE_BUTTON_CSS), timeout); + } - async saveChanges(): Promise { - Logger.debug(); + private async waitSaveButtonDisappearance( + attempts: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, + polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING + ): Promise { + await this.driverHelper.waitDisappearance(By.css(WorkspaceDetails.SAVE_BUTTON_CSS), attempts, polling); + } + + private async clickOnSaveButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.ENABLED_SAVE_BUTTON_CSS), timeout); + } + + private async clickOnOpenButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.OPEN_BUTTON_CSS), timeout); + } - await this.waitSaveButton(); - await this.clickOnSaveButton(); - await this.waitSaveButtonDisappearance(); - } - - async waitPage(workspaceName: string, timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug(`workspace: "${workspaceName}"`); - - await this.waitWorkspaceTitle(workspaceName, timeout); - await this.waitOpenButton(timeout); - await this.waitRunButton(timeout); - await this.waitTabsPresence(timeout); - await this.waitLoaderDisappearance(timeout); - } - - async waitWorkspaceTitle(workspaceName: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`title: "${workspaceName}"`); - - const workspaceTitleLocator: By = By.css(this.getWorkspaceTitleCssLocator(workspaceName)); - - await this.driverHelper.waitVisibility(workspaceTitleLocator, timeout); - } - - async waitRunButton(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(); - - await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.RUN_BUTTON_CSS), timeout); - } - - async clickOnRunButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(); - - await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.RUN_BUTTON_CSS), timeout); - } - - async waitOpenButton(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(); - - await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.OPEN_BUTTON_CSS), timeout); - } - - async openWorkspace(namespace: string, workspaceName: string, timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug(`"${namespace}/${workspaceName}"`); - - await this.clickOnOpenButton(timeout); - await this.testProjectAndFileCheCode.waitWorkspaceReadinessForCheCodeEditor(); - await this.testWorkspaceUtil.waitWorkspaceStatus(namespace, workspaceName, WorkspaceStatus.STARTING); - } - - async waitTabsPresence(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug('WorkspaceDetails.waitTabsPresence'); - - const workspaceDetailsTabs: Array = ['Overview', 'Projects', 'Containers', 'Servers', - 'Env Variables', 'Volumes', 'Config', 'SSH', 'Plugins', 'Editors']; - - for (const tabTitle of workspaceDetailsTabs) { - const workspaceDetailsTabLocator: By = By.xpath(this.getTabXpathLocator(tabTitle)); - - await this.driverHelper.waitVisibility(workspaceDetailsTabLocator, timeout); - } - } - - async selectTab(tabTitle: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`WorkspaceDetails.selectTab ${tabTitle}`); - - await this.clickOnTab(tabTitle, timeout); - await this.waitTabSelected(tabTitle, timeout); - } - - private getWorkspaceTitleCssLocator(workspaceName: string): string { - return `che-row-toolbar[che-title='${workspaceName}']`; - } - - private getTabXpathLocator(tabTitle: string): string { - return `//md-tabs-canvas//md-tab-item//span[text()='${tabTitle}']`; - } - - private getSelectedTabXpathLocator(tabTitle: string): string { - return `//md-tabs-canvas[@role='tablist']//md-tab-item[@aria-selected='true']//span[text()='${tabTitle}']`; - } - - private async waitSaveButton(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.ENABLED_SAVE_BUTTON_CSS), timeout); - } - - private async waitSaveButtonDisappearance(attempts: number = TimeoutConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING): Promise { - await this.driverHelper.waitDisappearance(By.css(WorkspaceDetails.SAVE_BUTTON_CSS), attempts, polling); - } - - private async clickOnSaveButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.ENABLED_SAVE_BUTTON_CSS), timeout); - } - - private async clickOnOpenButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.OPEN_BUTTON_CSS), timeout); - } - - private async clickOnTab(tabTitle: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - const workspaceDetailsTabLocator: By = By.xpath(this.getTabXpathLocator(tabTitle)); - - await this.driverHelper.waitAndClick(workspaceDetailsTabLocator, timeout); - } - - private async waitTabSelected(tabTitle: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - const selectedTabLocator: By = By.xpath(this.getSelectedTabXpathLocator(tabTitle)); - - await this.driverHelper.waitVisibility(selectedTabLocator, timeout); - } + private async clickOnTab(tabTitle: string, timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + const workspaceDetailsTabLocator: By = By.xpath(this.getTabXpathLocator(tabTitle)); + await this.driverHelper.waitAndClick(workspaceDetailsTabLocator, timeout); + } + + private async waitTabSelected(tabTitle: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + const selectedTabLocator: By = By.xpath(this.getSelectedTabXpathLocator(tabTitle)); + + await this.driverHelper.waitVisibility(selectedTabLocator, timeout); + } } diff --git a/tests/e2e/pageobjects/git-providers/OauthPage.ts b/tests/e2e/pageobjects/git-providers/OauthPage.ts index c7641f65dc9..d86da9e0d78 100644 --- a/tests/e2e/pageobjects/git-providers/OauthPage.ts +++ b/tests/e2e/pageobjects/git-providers/OauthPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -12,171 +12,182 @@ import { By } from 'selenium-webdriver'; import { CLASSES } from '../../configs/inversify.types'; import { DriverHelper } from '../../utils/DriverHelper'; import { Logger } from '../../utils/Logger'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; -import { FactoryTestConstants, GitProviderType } from '../../constants/FactoryTestConstants'; -import { OAuthConstants } from '../../constants/OAuthConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +import { FACTORY_TEST_CONSTANTS, GitProviderType } from '../../constants/FACTORY_TEST_CONSTANTS'; +import { OAUTH_CONSTANTS } from '../../constants/OAUTH_CONSTANTS'; @injectable() export class OauthPage { - private static LOGIN_FORM: By; - private static PASSWORD_FORM: By; - private static SUBMIT_BUTTON: By; - private static APPROVE_BUTTON: By; - private static DENY_ACCESS_BUTTON: By; - private static DENY_SAVE_CREDENTIALS_BUTTON: By; - - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { - switch (FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER) { - case GitProviderType.BITBUCKET : { - OauthPage.LOGIN_FORM = By.id('j_username'); - OauthPage.PASSWORD_FORM = By.id('j_password'); - OauthPage.APPROVE_BUTTON = By.id('approve'); - OauthPage.SUBMIT_BUTTON = By.id('submit'); - OauthPage.DENY_ACCESS_BUTTON = By.id('deny'); - } - break; - case GitProviderType.GITLAB: { - OauthPage.LOGIN_FORM = By.id('user_login'); - OauthPage.PASSWORD_FORM = By.id('user_password'); - OauthPage.SUBMIT_BUTTON = By.xpath('//button[@data-qa-selector="sign_in_button"]'); - OauthPage.APPROVE_BUTTON = By.xpath('//*[@value="Authorize"]'); - OauthPage.DENY_ACCESS_BUTTON = By.xpath('//input[@value="Deny"]'); - } - break; - case GitProviderType.GITHUB: { - OauthPage.LOGIN_FORM = By.id('login_field'); - OauthPage.PASSWORD_FORM = By.id('password'); - OauthPage.APPROVE_BUTTON = By.xpath('//*[@id="js-oauth-authorize-btn"]'); - OauthPage.SUBMIT_BUTTON = By.xpath('//*[@value="Sign in"]'); - OauthPage.DENY_ACCESS_BUTTON = By.xpath('//button[contains(., "Cancel")]'); - } - break; - case GitProviderType.AZURE_DEVOPS: { - OauthPage.LOGIN_FORM = By.xpath('//input[@type="email"]'); - OauthPage.PASSWORD_FORM = By.xpath('//input[@type="password"]'); - OauthPage.APPROVE_BUTTON = By.id('accept-button'); - OauthPage.SUBMIT_BUTTON = By.xpath('//input[@type="submit"]'); - OauthPage.DENY_SAVE_CREDENTIALS_BUTTON = By.xpath('//input[@type="button"]'); - OauthPage.DENY_ACCESS_BUTTON = By.id('deny-button'); - } - break; - default: { - throw new Error(`Invalid git provider. The value should be ${GitProviderType.GITHUB}, ${GitProviderType.GITLAB}, ${GitProviderType.AZURE_DEVOPS} or ${GitProviderType.BITBUCKET}`); - } - } - } - - async waitLoginPage(): Promise { - Logger.debug(); - - await this.driverHelper.waitVisibility(OauthPage.LOGIN_FORM, TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM * 3); - } - - async enterUserName(userName: string): Promise { - Logger.debug(`"${userName}"`); - - await this.driverHelper.enterValue(OauthPage.LOGIN_FORM, userName); - } - - async enterPassword(password: string): Promise { - Logger.debug(); - - await this.driverHelper.enterValue(OauthPage.PASSWORD_FORM, password); - } - - async clickOnSubmitButton(): Promise { - Logger.debug(); - - await this.driverHelper.waitAndClick(OauthPage.SUBMIT_BUTTON); - } - - async clickOnNotRememberCredentialsButton(): Promise { - Logger.debug(); - - await this.driverHelper.waitAndClick(OauthPage.DENY_SAVE_CREDENTIALS_BUTTON); - } - - async waitClosingLoginPage(): Promise { - Logger.debug(); - - await this.driverHelper.waitDisappearance(OauthPage.PASSWORD_FORM); - } - - async waitOauthPage(): Promise { - Logger.debug(); - - await this.driverHelper.waitVisibility(OauthPage.APPROVE_BUTTON); - } - - async clickOnApproveButton(): Promise { - Logger.debug(); - - await this.driverHelper.waitAndClick(OauthPage.APPROVE_BUTTON); - } - - async clickOnDenyAccessButton(): Promise { - Logger.debug(); - - await this.driverHelper.waitAndClick(OauthPage.DENY_ACCESS_BUTTON); - } - - async waitDisappearanceOauthPage(): Promise { - Logger.debug(); - - await this.driverHelper.waitDisappearance(OauthPage.APPROVE_BUTTON); - } - - async login(): Promise { - Logger.debug(); - - await this.waitLoginPage(); - await this.enterUserName(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_USERNAME); - if (FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.AZURE_DEVOPS) { - await this.clickOnSubmitButton(); - } - await this.enterPassword(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_PASSWORD); - await this.clickOnSubmitButton(); - if (FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.AZURE_DEVOPS) { - await this.clickOnNotRememberCredentialsButton(); - } - await this.waitClosingLoginPage(); - } - - async confirmAccess(): Promise { - Logger.debug(); - - try { - await this.clickOnApproveButton(); - await this.waitDisappearanceOauthPage(); - } catch (e) { - Logger.debug('access was not confirmed, retrying to click confirmation button'); - // workaround for GITHUB, AZURE_DEVOPS oauth confirmation page (bot security) - await this.driverHelper.getAction() - .move({ - origin: await this.driverHelper.waitPresence(OauthPage.APPROVE_BUTTON) - }) - .click() - .perform(); - await this.waitDisappearanceOauthPage(); - } - } - - async denyAccess(): Promise { - Logger.debug(); - - try { - await this.clickOnDenyAccessButton(); - await this.waitDisappearanceOauthPage(); - } catch (e) { - Logger.debug('deny access was not confirmed, retrying to click confirmation button'); - // workaround for GITHUB, AZURE_DEVOPS oauth confirmation page (bot security) - await this.driverHelper.getAction() - .move({ - origin: await this.driverHelper.waitPresence(OauthPage.DENY_ACCESS_BUTTON) - }) - .click() - .perform(); - await this.waitDisappearanceOauthPage(); - } - } + private static LOGIN_FORM: By; + private static PASSWORD_FORM: By; + private static SUBMIT_BUTTON: By; + private static APPROVE_BUTTON: By; + private static DENY_ACCESS_BUTTON: By; + private static DENY_SAVE_CREDENTIALS_BUTTON: By; + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) { + switch (FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER) { + case GitProviderType.BITBUCKET: + { + OauthPage.LOGIN_FORM = By.id('j_username'); + OauthPage.PASSWORD_FORM = By.id('j_password'); + OauthPage.APPROVE_BUTTON = By.id('approve'); + OauthPage.SUBMIT_BUTTON = By.id('submit'); + OauthPage.DENY_ACCESS_BUTTON = By.id('deny'); + } + break; + case GitProviderType.GITLAB: + { + OauthPage.LOGIN_FORM = By.id('user_login'); + OauthPage.PASSWORD_FORM = By.id('user_password'); + OauthPage.SUBMIT_BUTTON = By.xpath('//button[@data-qa-selector="sign_in_button"]'); + OauthPage.APPROVE_BUTTON = By.xpath('//*[@value="Authorize"]'); + OauthPage.DENY_ACCESS_BUTTON = By.xpath('//input[@value="Deny"]'); + } + break; + case GitProviderType.GITHUB: + { + OauthPage.LOGIN_FORM = By.id('login_field'); + OauthPage.PASSWORD_FORM = By.id('password'); + OauthPage.APPROVE_BUTTON = By.xpath('//*[@id="js-oauth-authorize-btn"]'); + OauthPage.SUBMIT_BUTTON = By.xpath('//*[@value="Sign in"]'); + OauthPage.DENY_ACCESS_BUTTON = By.xpath('//button[contains(., "Cancel")]'); + } + break; + case GitProviderType.AZURE_DEVOPS: + { + OauthPage.LOGIN_FORM = By.xpath('//input[@type="email"]'); + OauthPage.PASSWORD_FORM = By.xpath('//input[@type="password"]'); + OauthPage.APPROVE_BUTTON = By.id('accept-button'); + OauthPage.SUBMIT_BUTTON = By.xpath('//input[@type="submit"]'); + OauthPage.DENY_SAVE_CREDENTIALS_BUTTON = By.xpath('//input[@type="button"]'); + OauthPage.DENY_ACCESS_BUTTON = By.id('deny-button'); + } + break; + default: { + throw new Error( + `Invalid git provider. The value should be ${GitProviderType.GITHUB}, ${GitProviderType.GITLAB}, ${GitProviderType.AZURE_DEVOPS} or ${GitProviderType.BITBUCKET}` + ); + } + } + } + + async waitLoginPage(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(OauthPage.LOGIN_FORM, TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM * 3); + } + + async enterUserName(userName: string): Promise { + Logger.debug(`"${userName}"`); + + await this.driverHelper.enterValue(OauthPage.LOGIN_FORM, userName); + } + + async enterPassword(password: string): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(OauthPage.PASSWORD_FORM, password); + } + + async clickOnSubmitButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OauthPage.SUBMIT_BUTTON); + } + + async clickOnNotRememberCredentialsButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OauthPage.DENY_SAVE_CREDENTIALS_BUTTON); + } + + async waitClosingLoginPage(): Promise { + Logger.debug(); + + await this.driverHelper.waitDisappearance(OauthPage.PASSWORD_FORM); + } + + async waitOauthPage(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(OauthPage.APPROVE_BUTTON); + } + + async clickOnApproveButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OauthPage.APPROVE_BUTTON); + } + + async clickOnDenyAccessButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OauthPage.DENY_ACCESS_BUTTON); + } + + async waitDisappearanceOauthPage(): Promise { + Logger.debug(); + + await this.driverHelper.waitDisappearance(OauthPage.APPROVE_BUTTON); + } + + async login(): Promise { + Logger.debug(); + + await this.waitLoginPage(); + await this.enterUserName(OAUTH_CONSTANTS.TS_SELENIUM_GIT_PROVIDER_USERNAME); + if (FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.AZURE_DEVOPS) { + await this.clickOnSubmitButton(); + } + await this.enterPassword(OAUTH_CONSTANTS.TS_SELENIUM_GIT_PROVIDER_PASSWORD); + await this.clickOnSubmitButton(); + if (FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.AZURE_DEVOPS) { + await this.clickOnNotRememberCredentialsButton(); + } + await this.waitClosingLoginPage(); + } + + async confirmAccess(): Promise { + Logger.debug(); + + try { + await this.clickOnApproveButton(); + await this.waitDisappearanceOauthPage(); + } catch (e) { + Logger.debug('access was not confirmed, retrying to click confirmation button'); + // workaround for GITHUB, AZURE_DEVOPS oauth confirmation page (bot security) + await this.driverHelper + .getAction() + .move({ + origin: await this.driverHelper.waitPresence(OauthPage.APPROVE_BUTTON) + }) + .click() + .perform(); + await this.waitDisappearanceOauthPage(); + } + } + + async denyAccess(): Promise { + Logger.debug(); + + try { + await this.clickOnDenyAccessButton(); + await this.waitDisappearanceOauthPage(); + } catch (e) { + Logger.debug('deny access was not confirmed, retrying to click confirmation button'); + // workaround for GITHUB, AZURE_DEVOPS oauth confirmation page (bot security) + await this.driverHelper + .getAction() + .move({ + origin: await this.driverHelper.waitPresence(OauthPage.DENY_ACCESS_BUTTON) + }) + .click() + .perform(); + await this.waitDisappearanceOauthPage(); + } + } } diff --git a/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts b/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts index 2e7d4371c26..0baf6f26264 100644 --- a/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts +++ b/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -12,63 +12,66 @@ 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 { MonacoConstants } from '../../constants/MonacoConstants'; +import { MONACO_CONSTANTS } from '../../constants/MONACO_CONSTANTS'; /** - * This class allows us to change or add some specific locators base on "monaco-page-object" and "vscode-extension-tester-locators". + * 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; + readonly webCheCodeLocators: Locators; - constructor() { - super(MonacoConstants.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, MonacoConstants.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, getLocatorsPath()); - this.webCheCodeLocators = this.mergeLocators() as Locators; - } + constructor() { + super( + MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, + MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, + getLocatorsPath() + ); + this.webCheCodeLocators = this.mergeLocators(); + } - private webLocatorDiff(): LocatorDiff { - return { - locators: { - WelcomeContent: { - text: By.xpath('//*[@class="dialog-message-text" and contains(text(), "trust")]'), - button: By.xpath('//a[contains(., "trust")]') - } - }, - extras: { - ExtensionsViewSection: { - requireReloadButton: By.xpath('//a[text()=\'Reload Required\']') - } - } - }; - } + private webLocatorDiff(): LocatorDiff { + return { + locators: { + WelcomeContent: { + text: By.xpath('//*[@class="dialog-message-text" and contains(text(), "trust")]'), + button: By.xpath('//a[contains(., "trust")]') + } + }, + extras: { + ExtensionsViewSection: { + requireReloadButton: By.xpath('//a[text()="Reload Required"]') + } + } + }; + } - private merge(target: any, obj: any): object { - for (const key in obj) { - if (!Object.prototype.hasOwnProperty.call(obj, key)) { - continue; - } + private merge(target: any, obj: any): object { + for (const key in obj) { + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } - let oldVal: any = obj[key]; - let newVal: any = target[key]; + const oldVal: any = obj[key]; + const newVal: any = target[key]; - if (typeof (newVal) === 'object' && typeof (oldVal) === 'object') { - target[key] = this.merge(newVal, oldVal); - } else { - target[key] = clone(oldVal); - } - } - return target; - } + 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(); + private mergeLocators(): Locators { + const target: Locators = super.loadLocators(); - this.merge(target, this.webLocatorDiff().locators as Locators); - this.merge(target, this.webLocatorDiff().extras as Locators); + this.merge(target, this.webLocatorDiff().locators as Locators); + this.merge(target, this.webLocatorDiff().extras as Locators); - return target; - } + return target; + } } - diff --git a/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts b/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts index 24d388f073e..d5d8461319f 100644 --- a/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts +++ b/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -9,5 +9,5 @@ **********************************************************************/ export interface ICheLoginPage { - login(): void; + login(): Promise; } diff --git a/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts b/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts index 1c227104516..53deb4d786d 100644 --- a/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts +++ b/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -9,5 +9,5 @@ **********************************************************************/ export interface IOcpLoginPage { - login(): void; + login(): void; } diff --git a/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts b/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts index c53b793a31e..26662e12367 100644 --- a/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts +++ b/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -12,47 +12,48 @@ import { inject, injectable } from 'inversify'; import { CLASSES } from '../../../configs/inversify.types'; import { Logger } from '../../../utils/Logger'; import { By } from 'selenium-webdriver'; -import { TimeoutConstants } from '../../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; import { DriverHelper } from '../../../utils/DriverHelper'; @injectable() export class DexLoginPage { + private static readonly dexPageContentContainer: By = By.className('dex-container'); + private static readonly loginInput: By = By.id('login'); + private static readonly passwordInput: By = By.id('password'); + private static readonly submitButton: By = By.id('submit-login'); - private static readonly dexPageContentContainer: By = By.className('dex-container'); - private static readonly loginInput: By = By.id('login'); - private static readonly passwordInput: By = By.id('password'); - private static readonly submitButton: By = By.id('submit-login'); + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + async waitDexLoginPage(): Promise { + Logger.debug(); - async waitDexLoginPage(): Promise { - Logger.debug(); + await this.driverHelper.waitVisibility(DexLoginPage.dexPageContentContainer, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } - await this.driverHelper.waitVisibility(DexLoginPage.dexPageContentContainer, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + async clickOnLoginButton(): Promise { + Logger.debug(); - async clickOnLoginButton(): Promise { - Logger.debug(); + await this.driverHelper.waitAndClick(DexLoginPage.submitButton); + } - await this.driverHelper.waitAndClick(DexLoginPage.submitButton); - } + async enterUserNameKubernetes(userName: string): Promise { + Logger.debug(); - async enterUserNameKubernetes(userName: string): Promise { - Logger.debug(); + await this.driverHelper.enterValue(DexLoginPage.loginInput, userName); + } - await this.driverHelper.enterValue(DexLoginPage.loginInput, userName); - } + async enterPasswordKubernetes(password: string): Promise { + Logger.debug(); - async enterPasswordKubernetes(password: string): Promise { - Logger.debug(); + await this.driverHelper.enterValue(DexLoginPage.passwordInput, password); + } - await this.driverHelper.enterValue(DexLoginPage.passwordInput, password); - } + async waitDexLoginPageDisappearance(): Promise { + Logger.debug(); - async waitDexLoginPageDisappearance(): Promise { - Logger.debug(); - - await this.driverHelper.waitDisappearance(DexLoginPage.dexPageContentContainer, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + await this.driverHelper.waitDisappearance(DexLoginPage.dexPageContentContainer, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } } diff --git a/tests/e2e/pageobjects/login/kubernetes/KubernetesLoginPage.ts b/tests/e2e/pageobjects/login/kubernetes/KubernetesLoginPage.ts index 2188d4c5723..b208cf28038 100644 --- a/tests/e2e/pageobjects/login/kubernetes/KubernetesLoginPage.ts +++ b/tests/e2e/pageobjects/login/kubernetes/KubernetesLoginPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,21 +13,22 @@ import { CLASSES } from '../../../configs/inversify.types'; import { Logger } from '../../../utils/Logger'; import { ICheLoginPage } from '../interfaces/ICheLoginPage'; import { DexLoginPage } from './DexLoginPage'; -import { OAuthConstants } from '../../../constants/OAuthConstants'; +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; @injectable() export class KubernetesLoginPage implements ICheLoginPage { + constructor( + @inject(CLASSES.DexLoginPage) + private readonly dexLoginPage: DexLoginPage + ) {} - constructor( - @inject(CLASSES.DexLoginPage) private readonly dexLoginPage: DexLoginPage) { } + async login(): Promise { + Logger.debug(); - async login(): Promise { - Logger.debug(); - - await this.dexLoginPage.waitDexLoginPage(); - await this.dexLoginPage.enterUserNameKubernetes(OAuthConstants.TS_SELENIUM_K8S_USERNAME); - await this.dexLoginPage.enterPasswordKubernetes(OAuthConstants.TS_SELENIUM_K8S_PASSWORD); - await this.dexLoginPage.clickOnLoginButton(); - await this.dexLoginPage.waitDexLoginPageDisappearance(); - } + await this.dexLoginPage.waitDexLoginPage(); + await this.dexLoginPage.enterUserNameKubernetes(OAUTH_CONSTANTS.TS_SELENIUM_K8S_USERNAME); + await this.dexLoginPage.enterPasswordKubernetes(OAUTH_CONSTANTS.TS_SELENIUM_K8S_PASSWORD); + await this.dexLoginPage.clickOnLoginButton(); + await this.dexLoginPage.waitDexLoginPageDisappearance(); + } } diff --git a/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts b/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts index 472e8473e82..2893b0a46e4 100644 --- a/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,80 +13,87 @@ import { DriverHelper } from '../../../utils/DriverHelper'; import { CLASSES } from '../../../configs/inversify.types'; import { By } from 'selenium-webdriver'; import { Logger } from '../../../utils/Logger'; -import { TimeoutConstants } from '../../../constants/TimeoutConstants'; -import { OAuthConstants } from '../../../constants/OAuthConstants'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; @injectable() export class OcpLoginPage { + private static readonly LOGIN_PAGE_OPENSHIFT_XPATH: string = '//*[contains(text(), "Welcome")]'; - private static readonly LOGIN_PAGE_OPENSHIFT_XPATH: string = '//*[contains(text(), \'Welcome\')]'; + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + async waitOpenShiftLoginWelcomePage(): Promise { + Logger.debug(); - async waitOpenShiftLoginWelcomePage(): Promise { - Logger.debug(); + await this.driverHelper.waitVisibility( + By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH), + TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT + ); + } - await this.driverHelper.waitVisibility(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH), TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + async clickOnLoginProviderTitle(): Promise { + Logger.debug(); - async clickOnLoginProviderTitle(): Promise { - Logger.debug(); + const loginProviderTitleLocator: By = By.xpath(`//a[text()="${OAUTH_CONSTANTS.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}"]`); + await this.driverHelper.waitAndClick(loginProviderTitleLocator, TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL); + } - const loginProviderTitleLocator: By = By.xpath(`//a[text()=\'${OAuthConstants.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}\']`); - await this.driverHelper.waitAndClick(loginProviderTitleLocator, TimeoutConstants.TS_SELENIUM_WAIT_FOR_URL); - } + async isIdentityProviderLinkVisible(): Promise { + Logger.debug(); - async isIdentityProviderLinkVisible(): Promise { - Logger.debug(); + const loginWithHtpaswdLocator: By = By.xpath(`//a[text()="${OAUTH_CONSTANTS.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}"]`); + return await this.driverHelper.waitVisibilityBoolean(loginWithHtpaswdLocator, 3, 5000); + } - const loginWithHtpaswdLocator: By = By.xpath(`//a[text()=\'${OAuthConstants.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}\']`); - return await this.driverHelper.waitVisibilityBoolean(loginWithHtpaswdLocator, 3, 5000); - } + async isAuthorizeOpenShiftIdentityProviderPageVisible(): Promise { + Logger.debug(); - async isAuthorizeOpenShiftIdentityProviderPageVisible(): Promise { - Logger.debug(); + const authorizeOpenshiftIdentityProviderPageLocator: By = By.xpath('//h1[text()="Authorize Access"]'); + return await this.driverHelper.isVisible(authorizeOpenshiftIdentityProviderPageLocator); + } - const authorizeOpenshiftIdentityProviderPageLocator: By = By.xpath('//h1[text()=\'Authorize Access\']'); - return await this.driverHelper.isVisible(authorizeOpenshiftIdentityProviderPageLocator); - } + async waitAuthorizeOpenShiftIdentityProviderPage(): Promise { + Logger.debug(); - async waitAuthorizeOpenShiftIdentityProviderPage(): Promise { - Logger.debug(); + const authorizeOpenshiftIdentityProviderPageLocator: By = By.xpath('//h1[text()="Authorize Access"]'); + await this.driverHelper.waitVisibility( + authorizeOpenshiftIdentityProviderPageLocator, + TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT + ); + } - const authorizeOpenshiftIdentityProviderPageLocator: By = By.xpath('//h1[text()=\'Authorize Access\']'); - await this.driverHelper.waitVisibility(authorizeOpenshiftIdentityProviderPageLocator, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + async clickOnApproveAuthorizeAccessButton(): Promise { + Logger.debug(); - async clickOnApproveAuthorizeAccessButton(): Promise { - Logger.debug(); + const approveAuthorizeAccessOcpLocator: By = By.css('input[name="approve"]'); + await this.driverHelper.waitAndClick(approveAuthorizeAccessOcpLocator); + } - const approveAuthorizeAccessOcpLocator: By = By.css('input[name=\'approve\']'); - await this.driverHelper.waitAndClick(approveAuthorizeAccessOcpLocator); - } + async enterUserNameOpenShift(userName: string): Promise { + Logger.debug(`"${userName}"`); - async enterUserNameOpenShift(userName: string): Promise { - Logger.debug(`"${userName}"`); + await this.driverHelper.enterValue(By.id('inputUsername'), userName); + } - await this.driverHelper.enterValue(By.id('inputUsername'), userName); - } + async enterPasswordOpenShift(passw: string): Promise { + Logger.debug(); - async enterPasswordOpenShift(passw: string): Promise { - Logger.debug(); + await this.driverHelper.enterValue(By.id('inputPassword'), passw); + } - await this.driverHelper.enterValue(By.id('inputPassword'), passw); - } + async clickOnLoginButton(): Promise { + Logger.debug(); - async clickOnLoginButton(): Promise { - Logger.debug(); + const loginButtonLocator: By = By.css('button[type=submit]'); + await this.driverHelper.waitAndClick(loginButtonLocator); + } - const loginButtonLocator: By = By.css('button[type=submit]'); - await this.driverHelper.waitAndClick(loginButtonLocator); - } + async waitDisappearanceOpenShiftLoginWelcomePage(): Promise { + Logger.debug(); - async waitDisappearanceOpenShiftLoginWelcomePage(): Promise { - Logger.debug(); - - await this.driverHelper.waitDisappearance(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH)); - } + await this.driverHelper.waitDisappearance(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH)); + } } diff --git a/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts b/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts index d0cdc3b314f..9ff8eb36dfb 100644 --- a/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -12,7 +12,7 @@ import { inject, injectable } from 'inversify'; import { RedHatLoginPage } from './RedHatLoginPage'; import { CLASSES } from '../../../configs/inversify.types'; import { By } from 'selenium-webdriver'; -import { TimeoutConstants } from '../../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; import { ICheLoginPage } from '../interfaces/ICheLoginPage'; import { OcpLoginPage } from './OcpLoginPage'; import { DriverHelper } from '../../../utils/DriverHelper'; @@ -20,30 +20,35 @@ import { Logger } from '../../../utils/Logger'; @injectable() export class OcpRedHatLoginPage implements ICheLoginPage { + private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR: string = '//div[@class="panel-login"]'; + private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR: string = `${this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR}/div[contains(@class, 'panel-content')]/form/button`; - private 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 + ) {} - 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(); - async login(): Promise { - Logger.debug(); + Logger.debug('wait for LogInWithOpenShift page and click button'); + await this.driverHelper.waitPresence( + By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), + TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT + ); + await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); - Logger.debug('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.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(); - } + 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/openshift/OcpUserLoginPage.ts b/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts index c82c639ece9..cbc3645cdfe 100644 --- a/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,26 +13,23 @@ import { inject, injectable } from 'inversify'; import { OcpLoginPage } from './OcpLoginPage'; import { CLASSES } from '../../../configs/inversify.types'; import { Logger } from '../../../utils/Logger'; -import { OAuthConstants } from '../../../constants/OAuthConstants'; +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; @injectable() export class OcpUserLoginPage implements IOcpLoginPage { + constructor(@inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage) {} - constructor( - @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage) { } + async login(): Promise { + Logger.debug(); - async login(): Promise { - Logger.debug(); - - if (OAuthConstants.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE !== '') { - await this.ocpLogin.clickOnLoginProviderTitle(); - } - - await this.ocpLogin.waitOpenShiftLoginWelcomePage(); - await this.ocpLogin.enterUserNameOpenShift(OAuthConstants.TS_SELENIUM_OCP_USERNAME); - await this.ocpLogin.enterPasswordOpenShift(OAuthConstants.TS_SELENIUM_OCP_PASSWORD); - await this.ocpLogin.clickOnLoginButton(); - await this.ocpLogin.waitDisappearanceOpenShiftLoginWelcomePage(); - } + if (OAUTH_CONSTANTS.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE !== '') { + await this.ocpLogin.clickOnLoginProviderTitle(); + } + await this.ocpLogin.waitOpenShiftLoginWelcomePage(); + await this.ocpLogin.enterUserNameOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); + await this.ocpLogin.enterPasswordOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); + await this.ocpLogin.clickOnLoginButton(); + await this.ocpLogin.waitDisappearanceOpenShiftLoginWelcomePage(); + } } diff --git a/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts b/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts index 775dfaf0f17..2c3298d7f89 100644 --- a/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,51 +13,53 @@ import { By } from 'selenium-webdriver'; import { CLASSES } from '../../../configs/inversify.types'; import { DriverHelper } from '../../../utils/DriverHelper'; import { Logger } from '../../../utils/Logger'; -import { OAuthConstants } from '../../../constants/OAuthConstants'; +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; @injectable() export class RedHatLoginPage { - private readonly USERNAME_INPUT_ID: string = 'username-verification'; - private readonly PASSWORD_INPUT_ID: string = 'password'; - private readonly NEXT_BUTTON_ID: string = 'login-show-step2'; - private readonly LOGIN_BUTTON_ID: string = 'rh-password-verification-submit-button'; - - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } - - async waitRedHatLoginWelcomePage(): Promise { - Logger.debug(); - await this.driverHelper.waitVisibility(By.id(this.USERNAME_INPUT_ID)); - } - - async enterPasswordRedHat(): Promise { - Logger.debug(); - const passwordFieldLocator: By = By.id(this.PASSWORD_INPUT_ID); - await this.driverHelper.waitVisibility(passwordFieldLocator, 3000); - await this.driverHelper.enterValue(passwordFieldLocator, OAuthConstants.TS_SELENIUM_OCP_PASSWORD); - } - - async clickOnLoginButton(): Promise { - Logger.debug(); - const loginButtonLocator: By = By.id(this.LOGIN_BUTTON_ID); - await this.driverHelper.waitAndClick(loginButtonLocator); - } - - async waitDisappearanceRedHatLoginWelcomePage(): Promise { - Logger.debug(); - await this.driverHelper.waitDisappearance(By.id(this.LOGIN_BUTTON_ID)); - } - - async enterUserNameRedHat(): Promise { - Logger.debug(); - const usernameFieldLocator: By = By.id(this.USERNAME_INPUT_ID); - await this.driverHelper.waitVisibility(usernameFieldLocator, 20000); - await this.driverHelper.enterValue(usernameFieldLocator, OAuthConstants.TS_SELENIUM_OCP_USERNAME); - } - - async clickNextButton(): Promise { - Logger.debug(); - const nextButtonLocator: By = By.id(this.NEXT_BUTTON_ID); - await this.driverHelper.waitAndClick(nextButtonLocator); - } + private readonly USERNAME_INPUT_ID: string = 'username-verification'; + private readonly PASSWORD_INPUT_ID: string = 'password'; + private readonly NEXT_BUTTON_ID: string = 'login-show-step2'; + private readonly LOGIN_BUTTON_ID: string = 'rh-password-verification-submit-button'; + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async waitRedHatLoginWelcomePage(): Promise { + Logger.debug(); + await this.driverHelper.waitVisibility(By.id(this.USERNAME_INPUT_ID)); + } + + async enterPasswordRedHat(): Promise { + Logger.debug(); + const passwordFieldLocator: By = By.id(this.PASSWORD_INPUT_ID); + await this.driverHelper.waitVisibility(passwordFieldLocator, 3000); + await this.driverHelper.enterValue(passwordFieldLocator, OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); + } + + async clickOnLoginButton(): Promise { + Logger.debug(); + const loginButtonLocator: By = By.id(this.LOGIN_BUTTON_ID); + await this.driverHelper.waitAndClick(loginButtonLocator); + } + + async waitDisappearanceRedHatLoginWelcomePage(): Promise { + Logger.debug(); + await this.driverHelper.waitDisappearance(By.id(this.LOGIN_BUTTON_ID)); + } + + async enterUserNameRedHat(): Promise { + Logger.debug(); + const usernameFieldLocator: By = By.id(this.USERNAME_INPUT_ID); + await this.driverHelper.waitVisibility(usernameFieldLocator, 20000); + await this.driverHelper.enterValue(usernameFieldLocator, OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); + } + + async clickNextButton(): Promise { + Logger.debug(); + const nextButtonLocator: By = By.id(this.NEXT_BUTTON_ID); + await this.driverHelper.waitAndClick(nextButtonLocator); + } } diff --git a/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts b/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts index 1931561c442..478ee6ac448 100644 --- a/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts +++ b/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,41 +13,45 @@ import { OcpLoginPage } from './OcpLoginPage'; import { inject, injectable } from 'inversify'; import { CLASSES } from '../../../configs/inversify.types'; import { Logger } from '../../../utils/Logger'; -import { TimeoutConstants } from '../../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; import { By } from 'selenium-webdriver'; import { DriverHelper } from '../../../utils/DriverHelper'; -import { OAuthConstants } from '../../../constants/OAuthConstants'; +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; @injectable() export class RegularUserOcpCheLoginPage implements ICheLoginPage { - - private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR: string = `//div[@class='panel-login']`; - private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR: string = `${this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR}/div[contains(@class, 'panel-content')]/form/button`; - - constructor( - @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage, - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } - - async login(): Promise { - Logger.debug(); - - Logger.debug('wait for LogInWithOpenShift page and click button'); - await this.driverHelper.waitPresence(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); - - if (await this.ocpLogin.isIdentityProviderLinkVisible()) { - await this.ocpLogin.clickOnLoginProviderTitle(); - } - - await this.ocpLogin.waitOpenShiftLoginWelcomePage(); - await this.ocpLogin.enterUserNameOpenShift(OAuthConstants.TS_SELENIUM_OCP_USERNAME); - await this.ocpLogin.enterPasswordOpenShift(OAuthConstants.TS_SELENIUM_OCP_PASSWORD); - await this.ocpLogin.clickOnLoginButton(); - await this.ocpLogin.waitDisappearanceOpenShiftLoginWelcomePage(); - - if (await this.ocpLogin.isAuthorizeOpenShiftIdentityProviderPageVisible()) { - await this.ocpLogin.waitAuthorizeOpenShiftIdentityProviderPage(); - await this.ocpLogin.clickOnApproveAuthorizeAccessButton(); - } - } + 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.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async login(): Promise { + Logger.debug(); + + Logger.debug('wait for LogInWithOpenShift page and click button'); + await this.driverHelper.waitPresence( + By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), + TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT + ); + await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); + + if (await this.ocpLogin.isIdentityProviderLinkVisible()) { + await this.ocpLogin.clickOnLoginProviderTitle(); + } + + await this.ocpLogin.waitOpenShiftLoginWelcomePage(); + await this.ocpLogin.enterUserNameOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); + await this.ocpLogin.enterPasswordOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); + await this.ocpLogin.clickOnLoginButton(); + await this.ocpLogin.waitDisappearanceOpenShiftLoginWelcomePage(); + + if (await this.ocpLogin.isAuthorizeOpenShiftIdentityProviderPageVisible()) { + await this.ocpLogin.waitAuthorizeOpenShiftIdentityProviderPage(); + await this.ocpLogin.clickOnApproveAuthorizeAccessButton(); + } + } } diff --git a/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts b/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts index 7eca320785a..26a3a8c7f92 100644 --- a/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts +++ b/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,30 +13,31 @@ import { DriverHelper } from '../../utils/DriverHelper'; import { CLASSES } from '../../configs/inversify.types'; import { By } from 'selenium-webdriver'; import { Logger } from '../../utils/Logger'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; @injectable() export class OcpApplicationPage { + private static readonly APPLICATION_ICON_LOCATOR: By = By.xpath('//*[@data-test-id="base-node-handler"]'); + private static readonly EDIT_SOURCE_CODE_ICON_LOCATOR: By = By.xpath('//*[@aria-label="Edit source code"]'); - private static readonly APPLICATION_ICON_LOCATOR: By = By.xpath('//*[@data-test-id="base-node-handler"]'); - private static readonly EDIT_SOURCE_CODE_ICON_LOCATOR: By = By.xpath('//*[@aria-label="Edit source code"]'); + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper, + @inject(CLASSES.BrowserTabsUtil) + private readonly browserTabsUtil: BrowserTabsUtil + ) {} - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, - @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil) { - } + async waitApplicationIcon(): Promise { + Logger.debug(); - async waitApplicationIcon(): Promise { - Logger.debug(); + await this.driverHelper.waitPresence(OcpApplicationPage.APPLICATION_ICON_LOCATOR, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } - await this.driverHelper.waitPresence(OcpApplicationPage.APPLICATION_ICON_LOCATOR, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } - - async waitAndOpenEditSourceCodeIcon(): Promise { - Logger.debug(); - const parentGUID: string = await this.browserTabsUtil.getCurrentWindowHandle(); - await this.driverHelper.waitAndClick(OcpApplicationPage.EDIT_SOURCE_CODE_ICON_LOCATOR); - await this.browserTabsUtil.waitAndSwitchToAnotherWindow(parentGUID, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + async waitAndOpenEditSourceCodeIcon(): Promise { + Logger.debug(); + const parentGUID: string = await this.browserTabsUtil.getCurrentWindowHandle(); + await this.driverHelper.waitAndClick(OcpApplicationPage.EDIT_SOURCE_CODE_ICON_LOCATOR); + await this.browserTabsUtil.waitAndSwitchToAnotherWindow(parentGUID, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } } diff --git a/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts b/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts index 41676848e07..8645390c371 100644 --- a/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts +++ b/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -18,70 +18,72 @@ import { e2eContainer } from '../../configs/inversify.config'; @injectable() export class OcpImportFromGitPage { - - private static readonly GIT_URL_INPUT_LOCATOR: By = By.id('form-input-git-url-field'); - private static readonly SHOW_ADVANCED_GIT_OPTIONS_LINK_LOCATOR: By = By.xpath('//*[text()="Show advanced Git options"]//ancestor::button'); - private static readonly HIDE_ADVANCED_GIT_OPTIONS_LOCATOR: By = By.xpath('//*[text()="Hide advanced Git options"]'); - private static readonly GIT_REFERENCE_INPUT_LOCATOR: By = By.id('form-input-git-ref-field'); - private static readonly EDIT_IMPORT_STRATEGY_LINK_LOCATOR: By = By.xpath('//*[text()="Edit Import Strategy"]//ancestor::button'); - private static readonly BUILDER_IMAGE_STRATEGY_ITEM_LOCATOR: By = By.xpath('//*[text()="Builder Image"]//parent::div//parent::div'); - private static readonly ADD_LABEL_LINK_LOCATOR: By = By.xpath('//button[text()="Labels"]'); - private static readonly ADD_LABEL_INPUT_LOCATOR: By = By.id('form-selector-labels-field'); - private static readonly SUBMIT_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="submit-button"]'); - - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { - } - - async enterGitRepoUrl(gitRepoUrl: string): Promise { - Logger.debug(); - - await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_URL_INPUT_LOCATOR, gitRepoUrl); - } - - async clickOnAdvancedOptionsButton(): Promise { - Logger.debug(); - - if (!(await this.driverHelper.isVisible(OcpImportFromGitPage.HIDE_ADVANCED_GIT_OPTIONS_LOCATOR))) { - await this.driverHelper.waitAndClick(OcpImportFromGitPage.SHOW_ADVANCED_GIT_OPTIONS_LINK_LOCATOR); - } - } - - async enterGitReference(gitReference: string): Promise { - Logger.debug(`"${gitReference}"`); - - await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_REFERENCE_INPUT_LOCATOR, gitReference); - } - - async selectBuilderImageImportStrategy(): Promise { - Logger.debug(); - - await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.EDIT_IMPORT_STRATEGY_LINK_LOCATOR); - await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.BUILDER_IMAGE_STRATEGY_ITEM_LOCATOR); - } - - async addLabel(label: string): Promise { - Logger.debug(`"${label}"`); - - await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.ADD_LABEL_LINK_LOCATOR); - await this.driverHelper.scrollToAndEnterValue(OcpImportFromGitPage.ADD_LABEL_INPUT_LOCATOR, label); - } - - async submitConfiguration(): Promise { - Logger.debug(); - - await this.driverHelper.waitAndClick(OcpImportFromGitPage.SUBMIT_BUTTON_LOCATOR); - return e2eContainer.get(CLASSES.OcpApplicationPage); - } - - async fitAndSubmitConfiguration(gitRepoUrl: string, gitReference: string, label: string): Promise { - Logger.debug(); - - await this.enterGitRepoUrl(gitRepoUrl); - await this.clickOnAdvancedOptionsButton(); - await this.enterGitReference(gitReference); - await this.selectBuilderImageImportStrategy(); - await this.addLabel(label); - return await this.submitConfiguration(); - } + private static readonly GIT_URL_INPUT_LOCATOR: By = By.id('form-input-git-url-field'); + private static readonly SHOW_ADVANCED_GIT_OPTIONS_LINK_LOCATOR: By = By.xpath( + '//*[text()="Show advanced Git options"]//ancestor::button' + ); + private static readonly HIDE_ADVANCED_GIT_OPTIONS_LOCATOR: By = By.xpath('//*[text()="Hide advanced Git options"]'); + private static readonly GIT_REFERENCE_INPUT_LOCATOR: By = By.id('form-input-git-ref-field'); + private static readonly EDIT_IMPORT_STRATEGY_LINK_LOCATOR: By = By.xpath('//*[text()="Edit Import Strategy"]//ancestor::button'); + private static readonly BUILDER_IMAGE_STRATEGY_ITEM_LOCATOR: By = By.xpath('//*[text()="Builder Image"]//parent::div//parent::div'); + private static readonly ADD_LABEL_LINK_LOCATOR: By = By.xpath('//button[text()="Labels"]'); + private static readonly ADD_LABEL_INPUT_LOCATOR: By = By.id('form-selector-labels-field'); + private static readonly SUBMIT_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="submit-button"]'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async enterGitRepoUrl(gitRepoUrl: string): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_URL_INPUT_LOCATOR, gitRepoUrl); + } + + async clickOnAdvancedOptionsButton(): Promise { + Logger.debug(); + + if (!(await this.driverHelper.isVisible(OcpImportFromGitPage.HIDE_ADVANCED_GIT_OPTIONS_LOCATOR))) { + await this.driverHelper.waitAndClick(OcpImportFromGitPage.SHOW_ADVANCED_GIT_OPTIONS_LINK_LOCATOR); + } + } + + async enterGitReference(gitReference: string): Promise { + Logger.debug(`"${gitReference}"`); + + await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_REFERENCE_INPUT_LOCATOR, gitReference); + } + + async selectBuilderImageImportStrategy(): Promise { + Logger.debug(); + + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.EDIT_IMPORT_STRATEGY_LINK_LOCATOR); + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.BUILDER_IMAGE_STRATEGY_ITEM_LOCATOR); + } + + async addLabel(label: string): Promise { + Logger.debug(`"${label}"`); + + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.ADD_LABEL_LINK_LOCATOR); + await this.driverHelper.scrollToAndEnterValue(OcpImportFromGitPage.ADD_LABEL_INPUT_LOCATOR, label); + } + + async submitConfiguration(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OcpImportFromGitPage.SUBMIT_BUTTON_LOCATOR); + return e2eContainer.get(CLASSES.OcpApplicationPage); + } + + async fitAndSubmitConfiguration(gitRepoUrl: string, gitReference: string, label: string): Promise { + Logger.debug(); + + await this.enterGitRepoUrl(gitRepoUrl); + await this.clickOnAdvancedOptionsButton(); + await this.enterGitReference(gitReference); + await this.selectBuilderImageImportStrategy(); + await this.addLabel(label); + return await this.submitConfiguration(); + } } diff --git a/tests/e2e/pageobjects/openshift/OcpMainPage.ts b/tests/e2e/pageobjects/openshift/OcpMainPage.ts index ff30bbe0af2..9378a2c6930 100644 --- a/tests/e2e/pageobjects/openshift/OcpMainPage.ts +++ b/tests/e2e/pageobjects/openshift/OcpMainPage.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,97 +13,98 @@ import { DriverHelper } from '../../utils/DriverHelper'; import { CLASSES } from '../../configs/inversify.types'; import { By } from 'selenium-webdriver'; import { Logger } from '../../utils/Logger'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; import { OcpImportFromGitPage } from './OcpImportFromGitPage'; import { e2eContainer } from '../../configs/inversify.config'; @injectable() export class OcpMainPage { + private static readonly MAIN_PAGE_HEADER_LOCATOR: By = By.id('page-main-header'); + private static readonly SELECT_ROLE_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="perspective-switcher-toggle"]'); + private static readonly ADD_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="+Add-header"]'); + private static readonly IMPORT_FROM_GIT_ITEM_LOCATOR: By = By.xpath('//*[@data-test="item import-from-git"]'); + private static readonly SELECT_PROJECT_DROPDOWN_LOCATOR: By = By.xpath('//div[@class="co-namespace-dropdown"]//button'); + private static readonly PROJECT_FILTER_INPUT_LOCATOR: By = By.xpath('//*[@data-test="dropdown-text-filter"]'); + private static readonly SKIP_TOUR_BUTTON_LOCATOR: By = By.xpath('//*[text()="Skip tour"]'); - private static readonly MAIN_PAGE_HEADER_LOCATOR: By = By.id('page-main-header'); - private static readonly SELECT_ROLE_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="perspective-switcher-toggle"]'); - private static readonly ADD_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="+Add-header"]'); - private static readonly IMPORT_FROM_GIT_ITEM_LOCATOR: By = By.xpath('//*[@data-test="item import-from-git"]'); - private static readonly SELECT_PROJECT_DROPDOWN_LOCATOR: By = By.xpath('//div[@class="co-namespace-dropdown"]//button'); - private static readonly PROJECT_FILTER_INPUT_LOCATOR: By = By.xpath('//*[@data-test="dropdown-text-filter"]'); - private static readonly SKIP_TOUR_BUTTON_LOCATOR: By = By.xpath('//*[text()="Skip tour"]'); + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - private static getRoleLocator(role: string): By { - return By.xpath(`//a//*[text()="${role}"]`); - } + private static getRoleLocator(role: string): By { + return By.xpath(`//a//*[text()="${role}"]`); + } - private static getProjectDropdownItemLocator(projectName: string): By { - return By.xpath(`//button//*[text()="${projectName}"]`); - } + private static getProjectDropdownItemLocator(projectName: string): By { + return By.xpath(`//button//*[text()="${projectName}"]`); + } - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + async waitOpenMainPage(): Promise { + Logger.debug(); - async waitOpenMainPage(): Promise { - Logger.debug(); + await this.driverHelper.waitVisibility(OcpMainPage.MAIN_PAGE_HEADER_LOCATOR, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } - await this.driverHelper.waitVisibility(OcpMainPage.MAIN_PAGE_HEADER_LOCATOR, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + async clickOnSelectRoleButton(): Promise { + Logger.debug(); - async clickOnSelectRoleButton(): Promise { - Logger.debug(); + await this.driverHelper.waitAndClick(OcpMainPage.SELECT_ROLE_BUTTON_LOCATOR); + } - await this.driverHelper.waitAndClick(OcpMainPage.SELECT_ROLE_BUTTON_LOCATOR); - } + async clickAddToProjectButton(): Promise { + Logger.debug(); - async clickAddToProjectButton(): Promise { - Logger.debug(); + await this.driverHelper.waitAndClick(OcpMainPage.ADD_BUTTON_LOCATOR); + } - await this.driverHelper.waitAndClick(OcpMainPage.ADD_BUTTON_LOCATOR); - } + async selectDeveloperRole(): Promise { + Logger.debug(); - async selectDeveloperRole(): Promise { - Logger.debug(); + await this.waitOpenMainPage(); + await this.tryToSkipWebTour(); + await this.clickOnSelectRoleButton(); + await this.selectRole('Developer'); + await this.tryToSkipWebTour(); + } - await this.waitOpenMainPage(); - await this.tryToSkipWebTour(); - await this.clickOnSelectRoleButton(); - await this.selectRole('Developer'); - await this.tryToSkipWebTour(); - } + async selectImportFromGitMethod(): Promise { + Logger.debug(); - async selectImportFromGitMethod(): Promise { - Logger.debug(); + await this.driverHelper.waitAndClick(OcpMainPage.IMPORT_FROM_GIT_ITEM_LOCATOR); + return e2eContainer.get(CLASSES.OcpImportFromGitPage); + } - await this.driverHelper.waitAndClick(OcpMainPage.IMPORT_FROM_GIT_ITEM_LOCATOR); - return e2eContainer.get(CLASSES.OcpImportFromGitPage); - } + async openImportFromGitPage(): Promise { + Logger.debug(); - async openImportFromGitPage(): Promise { - Logger.debug(); + await this.clickAddToProjectButton(); + return await this.selectImportFromGitMethod(); + } - await this.clickAddToProjectButton(); - return await this.selectImportFromGitMethod(); - } + async selectProject(projectName: string): Promise { + Logger.debug(); - async selectProject(projectName: string): Promise { - Logger.debug(); + await this.driverHelper.waitAndClick(OcpMainPage.SELECT_PROJECT_DROPDOWN_LOCATOR); + await this.driverHelper.enterValue(OcpMainPage.PROJECT_FILTER_INPUT_LOCATOR, projectName); + await this.driverHelper.waitAndClick(OcpMainPage.getProjectDropdownItemLocator(projectName)); + } - await this.driverHelper.waitAndClick(OcpMainPage.SELECT_PROJECT_DROPDOWN_LOCATOR); - await this.driverHelper.enterValue(OcpMainPage.PROJECT_FILTER_INPUT_LOCATOR, projectName); - await this.driverHelper.waitAndClick(OcpMainPage.getProjectDropdownItemLocator(projectName)); - } + private async selectRole(role: string): Promise { + Logger.debug(`selecting role ${role}`); - private async selectRole(role: string): Promise { - Logger.debug(`selecting role ${role}`); + await this.driverHelper.waitAndClick(OcpMainPage.getRoleLocator(role)); + } - await this.driverHelper.waitAndClick(OcpMainPage.getRoleLocator(role)); - } + private async tryToSkipWebTour(): Promise { + Logger.debug(); - private async tryToSkipWebTour(): Promise { - Logger.debug(); + if (await this.driverHelper.isVisible(OcpMainPage.SKIP_TOUR_BUTTON_LOCATOR)) { + await this.driverHelper.waitAndClick(OcpMainPage.SKIP_TOUR_BUTTON_LOCATOR); - if (await this.driverHelper.isVisible(OcpMainPage.SKIP_TOUR_BUTTON_LOCATOR)) { - await this.driverHelper.waitAndClick(OcpMainPage.SKIP_TOUR_BUTTON_LOCATOR); - - Logger.debug(`welcome tour modal dialog was located and skipped`); - } else { - Logger.debug(`welcome tour modal dialog was not located`); - } - } + Logger.debug('welcome tour modal dialog was located and skipped'); + } else { + Logger.debug('welcome tour modal dialog was not located'); + } + } } diff --git a/tests/e2e/specs/MochaHooks.ts b/tests/e2e/specs/MochaHooks.ts index bbfa31359cb..898ecd6d07a 100644 --- a/tests/e2e/specs/MochaHooks.ts +++ b/tests/e2e/specs/MochaHooks.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2023 Red Hat, Inc. +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -11,16 +11,16 @@ import 'reflect-metadata'; import { CLASSES, TYPES } from '../configs/inversify.types'; import { CheApiRequestHandler } from '../utils/request-handlers/CheApiRequestHandler'; -import { TimeoutConstants } from '../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; import * as monacoPageObjects from 'monaco-page-objects'; import * as vscodeExtensionTesterLocators from 'vscode-extension-tester-locators'; import { e2eContainer } from '../configs/inversify.config'; import { DriverHelper } from '../utils/DriverHelper'; import { ITestWorkspaceUtil } from '../utils/workspace/ITestWorkspaceUtil'; import { Logger } from '../utils/Logger'; -import { BaseTestConstants } from '../constants/BaseTestConstants'; -import { ChromeDriverConstants } from '../constants/ChromeDriverConstants'; -import { MonacoConstants } from '../constants/MonacoConstants'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; +import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; +import { MONACO_CONSTANTS } from '../constants/MONACO_CONSTANTS'; const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); @@ -28,51 +28,60 @@ const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUt let latestWorkspace: string = ''; export function registerRunningWorkspace(workspaceName: string): void { - Logger.debug(`with workspaceName:${workspaceName}`); - latestWorkspace = workspaceName; + Logger.debug(`with workspaceName:${workspaceName}`); + latestWorkspace = workspaceName; } exports.mochaHooks = { - beforeAll: [ - async function enableRequestInterceptor(): Promise { - if (BaseTestConstants.TS_SELENIUM_REQUEST_INTERCEPTOR) { - CheApiRequestHandler.enableRequestInterceptor(); - } - }, - async function enableResponseInterceptor(): Promise { - if (BaseTestConstants.TS_SELENIUM_RESPONSE_INTERCEPTOR) { - CheApiRequestHandler.enableResponseInterceptor(); - } - }, - async function initMonacoPageObjects(): Promise { - // init vscode-extension-tester monaco-page-objects - monacoPageObjects.initPageObjects(MonacoConstants.TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION, MonacoConstants.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, vscodeExtensionTesterLocators.getLocatorsPath(), driverHelper.getDriver(), 'google-chrome'); - }, - async function prolongTimeoutConstantsInDebugMode(): Promise { - if (BaseTestConstants.TS_DEBUG_MODE) { - for (let [timeout, seconds] of Object.entries(TimeoutConstants)) { - Object.defineProperty(TimeoutConstants, timeout, { value: seconds as number * 100 }); - } - } - }, - ], - afterEach: [ - // stop and remove running workspace - async function(this: Mocha.Context): Promise { - if (this.currentTest?.state === 'failed') { - if (BaseTestConstants.DELETE_WORKSPACE_ON_FAILED_TEST) { - Logger.info('Property DELETE_WORKSPACE_ON_FAILED_TEST is true - trying to stop and delete running workspace with API.'); - await testWorkspaceUtil.stopAndDeleteWorkspaceByName(latestWorkspace); - } - } - }, - ], - afterAll: [ - async function stopTheDriver(): Promise { - if (!BaseTestConstants.TS_DEBUG_MODE && ChromeDriverConstants.TS_USE_WEB_DRIVER_FOR_TEST) { - await driverHelper.getDriver().quit(); - Logger.info('Chrome driver session stopped.'); - } - }, - ] + beforeAll: [ + function enableRequestInterceptor(): void { + if (BASE_TEST_CONSTANTS.TS_SELENIUM_REQUEST_INTERCEPTOR) { + CheApiRequestHandler.enableRequestInterceptor(); + } + }, + function enableResponseInterceptor(): void { + if (BASE_TEST_CONSTANTS.TS_SELENIUM_RESPONSE_INTERCEPTOR) { + CheApiRequestHandler.enableResponseInterceptor(); + } + }, + function initMonacoPageObjects(): void { + // init vscode-extension-tester monaco-page-objects + monacoPageObjects.initPageObjects( + MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION, + MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, + vscodeExtensionTesterLocators.getLocatorsPath(), + driverHelper.getDriver(), + 'google-chrome' + ); + }, + function prolongTimeoutConstantsInDebugMode(): void { + if (BASE_TEST_CONSTANTS.TS_DEBUG_MODE) { + for (const [timeout, seconds] of Object.entries(TIMEOUT_CONSTANTS)) { + Object.defineProperty(TIMEOUT_CONSTANTS, timeout, { + value: seconds * 100 + }); + } + } + } + ], + afterEach: [ + // stop and remove running workspace + function (this: Mocha.Context): void { + if (this.currentTest?.state === 'failed') { + if (BASE_TEST_CONSTANTS.DELETE_WORKSPACE_ON_FAILED_TEST) { + Logger.info('Property DELETE_WORKSPACE_ON_FAILED_TEST is true - trying to stop and delete running workspace with API.'); + // await + testWorkspaceUtil.stopAndDeleteWorkspaceByName(latestWorkspace); + } + } + } + ], + afterAll: [ + async function stopTheDriver(): Promise { + if (!BASE_TEST_CONSTANTS.TS_DEBUG_MODE && CHROME_DRIVER_CONSTANTS.TS_USE_WEB_DRIVER_FOR_TEST) { + await driverHelper.getDriver().quit(); + Logger.info('Chrome driver session stopped.'); + } + } + ] }; diff --git a/tests/e2e/specs/SmokeTest.spec.ts b/tests/e2e/specs/SmokeTest.spec.ts index 734e67bfe86..34492294a23 100644 --- a/tests/e2e/specs/SmokeTest.spec.ts +++ b/tests/e2e/specs/SmokeTest.spec.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2023 Red Hat, Inc. +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -16,50 +16,53 @@ import { registerRunningWorkspace } from './MochaHooks'; import { Logger } from '../utils/Logger'; import { LoginTests } from '../tests-library/LoginTests'; import { StringUtil } from '../utils/StringUtil'; -import { FactoryTestConstants } from '../constants/FactoryTestConstants'; +import { FACTORY_TEST_CONSTANTS } from '../constants/FACTORY_TEST_CONSTANTS'; import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; import { expect } from 'chai'; -import { BaseTestConstants } from '../constants/BaseTestConstants'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -suite(`The SmokeTest userstory`, async function(): Promise { - const factoryUrl: string = FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git'; - let projectSection: ViewSection; - suite(`Create workspace from factory:${factoryUrl}`, async function(): Promise { - loginTests.loginIntoChe(); - test(`Create and open new workspace from factory:${factoryUrl}`, async function(): Promise { - await workspaceHandlingTests.createAndOpenWorkspaceFromGitRepository(factoryUrl); - }); - test('Obtain workspace name from workspace loader page', async function(): Promise { - await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - }); - test('Register running workspace', async function(): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - test('Wait workspace readiness', async function(): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); - test('Check a project folder has been created', async function(): Promise { - const projectName: string = FactoryTestConstants.TS_SELENIUM_PROJECT_NAME || StringUtil.getProjectNameFromGitUrl(factoryUrl); - projectSection = await new SideBarView().getContent().getSection(projectName); - Logger.debug(`new SideBarView().getContent().getSection: get ${projectName}`); - }); - test('Check the project files was imported', async function(): Promise { - Logger.debug(`projectSection.findItem: find ${BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME}`); - const isFileImported: ViewItem | undefined = await projectSection.findItem(BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME); - expect(isFileImported).not.eqls(undefined); - }); - test('Stop the workspace', async function(): Promise { - await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - await browserTabsUtil.closeAllTabsExceptCurrent(); - }); - test('Delete the workspace', async function(): Promise { - await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - loginTests.logoutFromChe(); - }); +suite('The SmokeTest userstory', function (): void { + const factoryUrl: string = + FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git'; + let projectSection: ViewSection; + suite(`Create workspace from factory:${factoryUrl}`, function (): void { + loginTests.loginIntoChe(); + test(`Create and open new workspace from factory:${factoryUrl}`, async function (): Promise { + await workspaceHandlingTests.createAndOpenWorkspaceFromGitRepository(factoryUrl); + }); + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); + test('Register running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + test('Wait workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + test('Check a project folder has been created', async function (): Promise { + const projectName: string = FACTORY_TEST_CONSTANTS.TS_SELENIUM_PROJECT_NAME || StringUtil.getProjectNameFromGitUrl(factoryUrl); + projectSection = await new SideBarView().getContent().getSection(projectName); + Logger.debug(`new SideBarView().getContent().getSection: get ${projectName}`); + }); + test('Check the project files was imported', async function (): Promise { + Logger.debug(`projectSection.findItem: find ${BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME}`); + const isFileImported: ViewItem | undefined = await projectSection.findItem( + BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME + ); + expect(isFileImported).not.eqls(undefined); + }); + test('Stop the workspace', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + test('Delete the workspace', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + loginTests.logoutFromChe(); + }); }); diff --git a/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts b/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts index 92af847cfcf..07de2b69b6b 100644 --- a/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts +++ b/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts @@ -1,3 +1,12 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; import fs from 'fs'; import path from 'path'; @@ -5,34 +14,32 @@ import YAML from 'yaml'; import { expect } from 'chai'; import { ShellExecutor } from '../../utils/ShellExecutor'; -suite(`Test defining container overrides via attribute.`, async function(): Promise { - const pathToSampleFile: string = path.resolve('resources/container-overrides.yaml'); - const workspaceName: string = YAML.parse(fs.readFileSync(pathToSampleFile, 'utf8')).metadata.name; - const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(workspaceName); +suite('Test defining container overrides via attribute.', function (): void { + const pathToSampleFile: string = path.resolve('resources/container-overrides.yaml'); + const workspaceName: string = YAML.parse(fs.readFileSync(pathToSampleFile, 'utf8')).metadata.name; + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(workspaceName); - suiteSetup('Login into OC client', function(): void { - kubernetesCommandLineToolsExecutor.loginToOcp(); - }); + suiteSetup('Login into OC client', function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp(); + }); - suiteTeardown('Delete DevWorkspace', function(): void { - kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); - }); + suiteTeardown('Delete DevWorkspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); - test('Apply container-overrides sample as DevWorkspace with OC client', function(): void { - kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsFile(pathToSampleFile); - ShellExecutor.wait(5); - }); + test('Apply container-overrides sample as DevWorkspace with OC client', function (): void { + kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsFile(pathToSampleFile); + ShellExecutor.wait(5); + }); - test('Check that fields are overridden in the Deployment for DevWorkspace', function(): void { - const devWorkspaceFullYamlOutput: any = YAML.parse(kubernetesCommandLineToolsExecutor.getDevWorkspaceYamlConfiguration()); - expect(devWorkspaceFullYamlOutput.spec.template.components[0].attributes['container-overrides']).eqls({ - resources: { - limits: { - 'nvidia.com/gpu': '1' - } - } - }); - }); + test('Check that fields are overridden in the Deployment for DevWorkspace', function (): void { + const devWorkspaceFullYamlOutput: any = YAML.parse(kubernetesCommandLineToolsExecutor.getDevWorkspaceYamlConfiguration()); + expect(devWorkspaceFullYamlOutput.spec.template.components[0].attributes['container-overrides']).eqls({ + resources: { + limits: { + 'nvidia.com/gpu': '1' + } + } + }); + }); }); - - diff --git a/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts b/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts index 977dcb03f41..940d9c395da 100644 --- a/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts +++ b/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts @@ -1,3 +1,12 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigurationHelper'; import { ShellString } from 'shelljs'; @@ -8,101 +17,103 @@ import { StringUtil } from '../../utils/StringUtil'; import { Logger } from '../../utils/Logger'; /** - * Dynamically generating tests + * dynamically generating tests * info: https://mochajs.org/#delayed-root-suite */ - -(async function(): Promise { - - // todo: skipped while don`t use to avoid sending useless requests - // const devfilesRegistryHelper: DevfilesRegistryHelper = new DevfilesRegistryHelper(); - const devfileSamples: any = []; - // devfileSamples = await devfilesRegistryHelper.collectPathsToDevfilesFromRegistry(); - - for (const devfileSample of devfileSamples) { - suite.skip(`Devfile acceptance test suite for ${devfileSample.name}`, async function(): Promise { - this.bail(false); - this.timeout(1500000); // 25 minutes because build of Quarkus sample takes 20+ minutes - let devWorkspaceConfigurationHelper: DevWorkspaceConfigurationHelper; - let kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor; - let containerTerminal: KubernetesCommandLineToolsExecutor.ContainerTerminal; - let devfileContext: DevfileContext; - let devWorkspaceName: string | undefined; - let clonedProjectName: string; - let containerWorkDir: string; - let devfilesBuildCommands: any[] = []; - - test('Get DevWorkspace configuration', async function(): Promise { - devWorkspaceConfigurationHelper = new DevWorkspaceConfigurationHelper({ - devfileUrl: devfileSample.link - }); - devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext(); - devWorkspaceName = devfileContext?.devWorkspace?.metadata?.name; - - kubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(devWorkspaceName); - containerTerminal = new KubernetesCommandLineToolsExecutor.ContainerTerminal(kubernetesCommandLineToolsExecutor); - kubernetesCommandLineToolsExecutor.loginToOcp(); - }); - - test('Collect build commands from the devfile', async function(): Promise { - if (devfileContext.devfile.commands === undefined) { - Logger.info(`Devfile does not contains any commands.`); - } else { - devfileContext.devfile.commands.forEach((command: any) => { - if (command.exec?.group?.kind === 'build') { - Logger.debug(`Build command found: ${command.exec.commandLine}`); - devfilesBuildCommands.push(command); - } - }); - } - }); - - test('Create DevWorkspace', async function(): Promise { - const devWorkspaceConfigurationYamlString: string = await devWorkspaceConfigurationHelper.getDevWorkspaceConfigurationYamlAsString(devfileContext); - const applyOutput: ShellString = kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsStringOutput(devWorkspaceConfigurationYamlString); - - expect(applyOutput.stdout) - .contains('devworkspacetemplate') - .and.contains('devworkspace') - .and.contains.oneOf(['created', 'configured']); - - }); - - test('Wait until DevWorkspace has status "ready"', async function(): Promise { - expect(kubernetesCommandLineToolsExecutor.waitDevWorkspace().stdout).contains('condition met'); - }); - - test('Check if project was created', function(): void { - clonedProjectName = StringUtil.getProjectNameFromGitUrl(devfileSample.link); - expect(containerTerminal.ls().stdout).includes(clonedProjectName); - }); - - test('Check if project files are imported', function(): void { - containerWorkDir = containerTerminal.pwd().stdout.replace('\n', ''); - expect(containerTerminal.ls(`${containerWorkDir}/${clonedProjectName}`).stdout).includes(`devfile.yaml`); - }); - - test(`Check if build commands returns success`, function(): void { - if (devfilesBuildCommands.length === 0) { - Logger.info(`Devfile does not contains build commands.`); - } else { - devfilesBuildCommands.forEach((command) => { - Logger.info(`command.exec: ${JSON.stringify(command.exec)}`); - - const commandString: string = StringUtil.updateCommandEnvsToShStyle(`cd ${command.exec.workingDir} && ${command.exec.commandLine}`); - Logger.info(`Full build command to be executed: ${commandString}`); - - const output: ShellString = containerTerminal.executeCommand(commandString, command.exec.component); - expect(output.code).eqls(0); - }); - } - }); - - test('Delete DevWorkspace', async function(): Promise { - kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); - }); - }); - } - - run(); +// todo: skipped while don`t use to avoid sending useless requests +// eslint-disable-next-line @typescript-eslint/require-await +void (async function (): Promise { + // const devfilesRegistryHelper: DevfilesRegistryHelper = new DevfilesRegistryHelper(); + const devfileSamples: any = []; + // devfileSamples = await devfilesRegistryHelper.collectPathsToDevfilesFromRegistry(); + + for (const devfileSample of devfileSamples) { + suite.skip(`Devfile acceptance test suite for ${devfileSample.name}`, function (): void { + this.bail(false); + this.timeout(1500000); // 25 minutes because build of Quarkus sample takes 20+ minutes + let devWorkspaceConfigurationHelper: DevWorkspaceConfigurationHelper; + let kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor; + let containerTerminal: KubernetesCommandLineToolsExecutor.ContainerTerminal; + let devfileContext: DevfileContext; + let devWorkspaceName: string | undefined; + let clonedProjectName: string; + let containerWorkDir: string; + const devfilesBuildCommands: any[] = []; + + test('Get DevWorkspace configuration', async function (): Promise { + devWorkspaceConfigurationHelper = new DevWorkspaceConfigurationHelper({ + devfileUrl: devfileSample.link + }); + devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext(); + devWorkspaceName = devfileContext?.devWorkspace?.metadata?.name; + + kubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(devWorkspaceName); + containerTerminal = new KubernetesCommandLineToolsExecutor.ContainerTerminal(kubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor.loginToOcp(); + }); + + test('Collect build commands from the devfile', function (): void { + if (devfileContext.devfile.commands === undefined) { + Logger.info('Devfile does not contains any commands.'); + } else { + devfileContext.devfile?.commands?.forEach((command: any): void => { + if (command.exec?.group?.kind === 'build') { + Logger.debug(`Build command found: ${command.exec.commandLine}`); + devfilesBuildCommands.push(command); + } + }); + } + }); + + test('Create DevWorkspace', function (): void { + const devWorkspaceConfigurationYamlString: string = + devWorkspaceConfigurationHelper.getDevWorkspaceConfigurationYamlAsString(devfileContext); + const applyOutput: ShellString = + kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsStringOutput(devWorkspaceConfigurationYamlString); + + expect(applyOutput.stdout) + .contains('devworkspacetemplate') + .and.contains('devworkspace') + .and.contains.oneOf(['created', 'configured']); + }); + + test('Wait until DevWorkspace has status "ready"', function (): void { + expect(kubernetesCommandLineToolsExecutor.waitDevWorkspace().stdout).contains('condition met'); + }); + + test('Check if project was created', function (): void { + clonedProjectName = StringUtil.getProjectNameFromGitUrl(devfileSample.link); + expect(containerTerminal.ls().stdout).includes(clonedProjectName); + }); + + test('Check if project files are imported', function (): void { + containerWorkDir = containerTerminal.pwd().stdout.replace('\n', ''); + expect(containerTerminal.ls(`${containerWorkDir}/${clonedProjectName}`).stdout).includes('devfile.yaml'); + }); + + test('Check if build commands returns success', function (): void { + if (devfilesBuildCommands.length === 0) { + Logger.info('Devfile does not contains build commands.'); + } else { + devfilesBuildCommands.forEach((command): void => { + Logger.info(`command.exec: ${JSON.stringify(command.exec)}`); + + const commandString: string = StringUtil.updateCommandEnvsToShStyle( + `cd ${command.exec.workingDir} && ${command.exec.commandLine}` + ); + Logger.info(`Full build command to be executed: ${commandString}`); + + const output: ShellString = containerTerminal.executeCommand(commandString, command.exec.component); + expect(output.code).eqls(0); + }); + } + }); + + test('Delete DevWorkspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); + }); + } + + run(); })(); diff --git a/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts b/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts index 43da6543321..c390dcb9590 100644 --- a/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts +++ b/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts @@ -1,74 +1,79 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; import { expect } from 'chai'; import { ShellString } from 'shelljs'; import { StringUtil } from '../../utils/StringUtil'; import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigurationHelper'; import { DevfileContext } from '@eclipse-che/che-devworkspace-generator/lib/api/devfile-context'; -import { APITestConstants } from '../../constants/APITestConstants'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; +import { API_TEST_CONSTANTS } from '../../constants/API_TEST_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; -suite(`Empty workspace API test`, async function(): Promise { - // works only for root user - const namespace: string = APITestConstants.TS_API_TEST_NAMESPACE; - let clonedProjectName: string; - let containerWorkDir: string; - let devWorkspaceConfigurationHelper: DevWorkspaceConfigurationHelper; - let kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor; - let devfileContext: DevfileContext; - let devWorkspaceName: string | undefined; - let containerTerminal: KubernetesCommandLineToolsExecutor.ContainerTerminal; +suite('Empty workspace API test', function (): void { + // works only for root user + const namespace: string | undefined = API_TEST_CONSTANTS.TS_API_TEST_NAMESPACE; + let clonedProjectName: string; + let containerWorkDir: string; + let devWorkspaceConfigurationHelper: DevWorkspaceConfigurationHelper; + let kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor; + let devfileContext: DevfileContext; + let devWorkspaceName: string | undefined; + let containerTerminal: KubernetesCommandLineToolsExecutor.ContainerTerminal; - const gitRepository: string = 'https://github.com/crw-qe/web-nodejs-sample'; + const gitRepository: string = 'https://github.com/crw-qe/web-nodejs-sample'; - suiteSetup('Create empty workspace with OC client', async function(): Promise { - const workspaceName: string = 'empty-' + Math.floor(Math.random() * 1000); - const devfileContent: string = - 'schemaVersion: 2.2.0\n' + - 'metadata:\n' + - ` name: ${workspaceName}\n`; + suiteSetup('Create empty workspace with OC client', async function (): Promise { + const workspaceName: string = 'empty-' + Math.floor(Math.random() * 1000); + const devfileContent: string = 'schemaVersion: 2.2.0\n' + 'metadata:\n' + ` name: ${workspaceName}\n`; - devWorkspaceConfigurationHelper = new DevWorkspaceConfigurationHelper({ - devfileContent - }); - devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext(); - devWorkspaceName = devfileContext?.devWorkspace?.metadata?.name; - kubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(devWorkspaceName, namespace); - containerTerminal = new KubernetesCommandLineToolsExecutor.ContainerTerminal(kubernetesCommandLineToolsExecutor); - }); + devWorkspaceConfigurationHelper = new DevWorkspaceConfigurationHelper({ + devfileContent + }); + devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext(); + devWorkspaceName = devfileContext?.devWorkspace?.metadata?.name; + kubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(devWorkspaceName, namespace); + containerTerminal = new KubernetesCommandLineToolsExecutor.ContainerTerminal(kubernetesCommandLineToolsExecutor); + }); - test('Create empty workspace', async function(): Promise { - kubernetesCommandLineToolsExecutor.loginToOcp(); - const devWorkspaceConfigurationYamlString: string = await devWorkspaceConfigurationHelper.getDevWorkspaceConfigurationYamlAsString(devfileContext); - const output: ShellString = kubernetesCommandLineToolsExecutor.applyAndWaitDevWorkspace(devWorkspaceConfigurationYamlString); - expect(output.stdout).contains('condition met'); - }); + test('Create empty workspace', function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp(); + const devWorkspaceConfigurationYamlString: string = + devWorkspaceConfigurationHelper.getDevWorkspaceConfigurationYamlAsString(devfileContext); + const output: ShellString = kubernetesCommandLineToolsExecutor.applyAndWaitDevWorkspace(devWorkspaceConfigurationYamlString); + expect(output.stdout).contains('condition met'); + }); - suite('Clone public repo without previous setup', function(): void { + suite('Clone public repo without previous setup', function (): void { + test('Check if public repo can be cloned', function (): void { + containerWorkDir = containerTerminal.pwd().stdout.replace('\n', ''); + const cloneOutput: ShellString = containerTerminal.gitClone(gitRepository); + expect(cloneOutput.stdout + cloneOutput.stderr).includes('Cloning'); + }); - test('Check if public repo can be cloned', function(): void { - containerWorkDir = containerTerminal.pwd().stdout.replace('\n', ''); - const cloneOutput: ShellString = containerTerminal.gitClone(gitRepository); - expect(cloneOutput.stdout + cloneOutput.stderr).includes('Cloning'); - }); + test('Check if project was created', function (): void { + clonedProjectName = StringUtil.getProjectNameFromGitUrl(gitRepository); + expect(containerTerminal.ls().stdout).includes(clonedProjectName); + }); - test('Check if project was created', function(): void { - clonedProjectName = StringUtil.getProjectNameFromGitUrl(gitRepository); - expect(containerTerminal.ls().stdout).includes(clonedProjectName); - }); + test('Check if project files are imported', function (): void { + expect(containerTerminal.ls(`${containerWorkDir}/${clonedProjectName}`).stdout).includes( + BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME + ); + }); - test('Check if project files are imported', function(): void { - expect(containerTerminal.ls(`${containerWorkDir}/${clonedProjectName}`).stdout) - .includes(BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME); - }); + suiteTeardown('Delete cloned project', function (): void { + containerTerminal.removeFolder(`${clonedProjectName}`); + }); + }); - suiteTeardown('Delete cloned project', function(): void { - containerTerminal.removeFolder(`${clonedProjectName}`); - }); - }); - - suiteTeardown('Delete workspace', function(): void { - kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); - }); + suiteTeardown('Delete workspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); }); - - diff --git a/tests/e2e/specs/api/PodOverridesAPI.spec.ts b/tests/e2e/specs/api/PodOverridesAPI.spec.ts index 985b9369c8c..b898526da9a 100644 --- a/tests/e2e/specs/api/PodOverridesAPI.spec.ts +++ b/tests/e2e/specs/api/PodOverridesAPI.spec.ts @@ -1,45 +1,54 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; import fs from 'fs'; import path from 'path'; import YAML from 'yaml'; import { expect } from 'chai'; import { ShellExecutor } from '../../utils/ShellExecutor'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; -suite(`Test defining pod overrides via attribute.`, async function(): Promise { - const pathToSampleFile: string = path.resolve(`resources/pod-overrides${BaseTestConstants.IS_CLUSTER_DISCONNECTED() ? '-airgap' : ''}.yaml`); - const workspaceName: string = YAML.parse(fs.readFileSync(pathToSampleFile, 'utf8')).metadata.name; - const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(workspaceName); +suite('Test defining pod overrides via attribute.', function (): void { + const pathToSampleFile: string = path.resolve( + `resources/pod-overrides${BASE_TEST_CONSTANTS.IS_CLUSTER_DISCONNECTED() ? '-airgap' : ''}.yaml` + ); + const workspaceName: string = YAML.parse(fs.readFileSync(pathToSampleFile, 'utf8')).metadata.name; + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(workspaceName); - suiteSetup('Login into OC client', function(): void { - kubernetesCommandLineToolsExecutor.loginToOcp(); - }); + suiteSetup('Login into OC client', function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp(); + }); - suiteTeardown('Delete DevWorkspace', function(): void { - kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); - }); + suiteTeardown('Delete DevWorkspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); - test('Apply pod-overrides sample as DevWorkspace with OC client', function(): void { - kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsFile(pathToSampleFile); - ShellExecutor.wait(5); - }); + test('Apply pod-overrides sample as DevWorkspace with OC client', function (): void { + kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsFile(pathToSampleFile); + ShellExecutor.wait(5); + }); - test('Check that fields are overridden in the Deployment for DevWorkspace', function(): void { - const devWorkspaceFullYamlOutput: any = YAML.parse(kubernetesCommandLineToolsExecutor.getDevWorkspaceYamlConfiguration()); - expect(devWorkspaceFullYamlOutput.spec.template.attributes['pod-overrides']).eqls({ - metadata: { - annotations: { - 'io.kubernetes.cri-o.userns-mode': 'auto:size=65536;map-to-root=true', - 'io.openshift.userns': 'true', - 'openshift.io/scc': 'container-build' - } - }, - spec: { - runtimeClassName: 'kata', - schedulerName: 'stork' - } - }); - }); + test('Check that fields are overridden in the Deployment for DevWorkspace', function (): void { + const devWorkspaceFullYamlOutput: any = YAML.parse(kubernetesCommandLineToolsExecutor.getDevWorkspaceYamlConfiguration()); + expect(devWorkspaceFullYamlOutput.spec.template.attributes['pod-overrides']).eqls({ + metadata: { + annotations: { + 'io.kubernetes.cri-o.userns-mode': 'auto:size=65536;map-to-root=true', + 'io.openshift.userns': 'true', + 'openshift.io/scc': 'container-build' + } + }, + spec: { + runtimeClassName: 'kata', + schedulerName: 'stork' + } + }); + }); }); - - diff --git a/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts b/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts index ee57907973a..b976ec3798c 100644 --- a/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts +++ b/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2020-2023 Red Hat, Inc. +/** ******************************************************************* + * copyright (c) 2020-2023 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -24,42 +24,42 @@ const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUti const stackName: string = 'Empty Workspace'; -suite(`${stackName} test`, async function(): Promise { - loginTests.loginIntoChe(); +suite(`${stackName} test`, function (): void { + loginTests.loginIntoChe(); - test(`Create and open new workspace, stack:${stackName}`, async function(): Promise { - await workspaceHandlingTests.createAndOpenWorkspace(stackName); - }); + test(`Create and open new workspace, stack:${stackName}`, async function (): Promise { + await workspaceHandlingTests.createAndOpenWorkspace(stackName); + }); - test('Obtain workspace name from workspace loader page', async function(): Promise { - await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - }); + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); - test('Register running workspace', async function(): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + test('Register running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - test('Wait workspace readiness', async function(): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + test('Wait workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - const workbench: Workbench = new Workbench(); - const activityBar: ActivityBar = workbench.getActivityBar(); - const activityBarControls: ViewControl[] = await activityBar.getViewControls(); + const workbench: Workbench = new Workbench(); + const activityBar: ActivityBar = workbench.getActivityBar(); + const activityBarControls: ViewControl[] = await activityBar.getViewControls(); - Logger.debug(`Editor sections:`); - for (const control of activityBarControls) { - Logger.debug(`${await control.getTitle()}`); - } - }); + Logger.debug('Editor sections:'); + for (const control of activityBarControls) { + Logger.debug(`${await control.getTitle()}`); + } + }); - test('Stop the workspace', async function(): Promise { - await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - await browserTabsUtil.closeAllTabsExceptCurrent(); - }); + test('Stop the workspace', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); - test('Delete the workspace', async function(): Promise { - await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + test('Delete the workspace', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - loginTests.logoutFromChe(); + loginTests.logoutFromChe(); }); diff --git a/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts b/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts index 67abbe0b6c7..42d4b9c6ea6 100644 --- a/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts +++ b/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -16,7 +16,7 @@ import { CLASSES } from '../../configs/inversify.types'; import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; import { Logger } from '../../utils/Logger'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); @@ -27,44 +27,44 @@ const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUti const stackName: string = 'Java 11 with Quarkus'; const projectName: string = 'quarkus-quickstarts'; -suite(`The ${stackName} userstory`, async function(): Promise { - let projectSection: ViewSection; +suite(`The ${stackName} userstory`, function (): void { + let projectSection: ViewSection; - loginTests.loginIntoChe(); + loginTests.loginIntoChe(); - test(`Create and open new workspace, stack:${stackName}`, async function(): Promise { - await workspaceHandlingTests.createAndOpenWorkspace(stackName); - }); + test(`Create and open new workspace, stack:${stackName}`, async function (): Promise { + await workspaceHandlingTests.createAndOpenWorkspace(stackName); + }); - test('Obtain workspace name from workspace loader page', async function(): Promise { - await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - }); + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); - test('Register running workspace', async function(): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + test('Register running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - test('Wait workspace readiness', async function(): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); + test('Wait workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); - test('Check a project folder has been created', async function(): Promise { - projectSection = await new SideBarView().getContent().getSection(projectName); - Logger.debug(`new SideBarView().getContent().getSection: get ${projectName}`); - }); + test('Check a project folder has been created', async function (): Promise { + projectSection = await new SideBarView().getContent().getSection(projectName); + Logger.debug(`new SideBarView().getContent().getSection: get ${projectName}`); + }); - test('Check the project files was imported', async function(): Promise { - await projectSection.findItem(BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME); - Logger.debug(`projectSection.findItem: find ${BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME}`); - }); + test('Check the project files was imported', async function (): Promise { + await projectSection.findItem(BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME); + Logger.debug(`projectSection.findItem: find ${BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME}`); + }); - test('Stop the workspace', async function(): Promise { - await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - await browserTabsUtil.closeAllTabsExceptCurrent(); - }); + test('Stop the workspace', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); - test('Delete the workspace', async function(): Promise { - await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - loginTests.logoutFromChe(); + test('Delete the workspace', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + loginTests.logoutFromChe(); }); diff --git a/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts b/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts index c7b3375addb..4b0dc5000c9 100644 --- a/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts +++ b/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -9,18 +9,18 @@ **********************************************************************/ import { - ActivityBar, - ContextMenu, - ContextMenuItem, - EditorView, - ExtensionsViewItem, - ExtensionsViewSection, - Locators, - ModalDialog, - SideBarView, - TextEditor, - ViewItem, - ViewSection + ActivityBar, + ContextMenu, + ContextMenuItem, + EditorView, + ExtensionsViewItem, + ExtensionsViewSection, + Locators, + ModalDialog, + SideBarView, + TextEditor, + ViewItem, + ViewSection } from 'monaco-page-objects'; import { registerRunningWorkspace } from '../MochaHooks'; import { LoginTests } from '../../tests-library/LoginTests'; @@ -32,10 +32,10 @@ import { Logger } from '../../utils/Logger'; import { DriverHelper } from '../../utils/DriverHelper'; import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; import { expect } from 'chai'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; -import { PluginsTestConstants } from '../../constants/PluginsTestConstants'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; +import { PLUGIN_TEST_CONSTANTS } from '../../constants/PLUGIN_TEST_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); @@ -43,163 +43,181 @@ const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; -const samples: string[] = PluginsTestConstants.TS_SAMPLE_LIST.split(','); +const samples: string[] = PLUGIN_TEST_CONSTANTS.TS_SAMPLE_LIST.split(','); const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -suite(`Check if recommended extensions installed for ${samples}`, async function(): Promise { - let projectSection: ViewSection; - let extensionsView: SideBarView | undefined; - let extensionSection: ExtensionsViewSection; - - const extensionsListFileName: string = 'extensions.json'; - let recommendedExtensions: any = { - recommendations: [] - }; - - loginTests.loginIntoChe(); - - for (const sample of samples) { - test(`Create and open new workspace, stack:${sample}`, async function(): Promise { - await workspaceHandlingTests.createAndOpenWorkspace(sample); - }); - test('Obtain workspace name from workspace loader page', async function(): Promise { - await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - }); - - test('Registering the running workspace', async function(): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - - test('Wait workspace readiness', async function(): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); - - test('Wait until the project will be imported and accept it as trusted one', async function(): Promise { - [projectSection] = await new SideBarView().getContent().getSections(); - const label: string = BaseTestConstants.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); - try { - const buttonYesITrustTheAuthors: string = `Yes, I trust the authors`; - await driverHelper.waitVisibility(webCheCodeLocators.WelcomeContent.button, TimeoutConstants.TS_DIALOG_WINDOW_DEFAULT_TIMEOUT); - const trustedProjectDialog: ModalDialog = new ModalDialog(); - Logger.debug(`trustedProjectDialog.pushButton: "${buttonYesITrustTheAuthors}"`); - await trustedProjectDialog.pushButton(buttonYesITrustTheAuthors); - } catch (e) { - Logger.debug(`Welcome modal dialog was not shown: ${e}`); - } - }); - - test(`Get recommended extensions list from ${extensionsListFileName}`, async function(): Promise { - Logger.debug(`projectSection.findItem(item))?.select(): expand .vscode folder and open extensions.json.`); - await (await projectSection.findItem('.vscode'))?.select(); - // time to expand project tree - await driverHelper.wait(TimeoutConstants.TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT); - await (await projectSection.findItem(extensionsListFileName))?.select(); - Logger.debug(`EditorView().openEditor(${extensionsListFileName})`); - const editor: TextEditor = await new EditorView().openEditor(extensionsListFileName) as TextEditor; - await driverHelper.waitVisibility(webCheCodeLocators.Editor.inputArea); - Logger.debug(`editor.getText(): get recommended extensions as text from editor, delete comments and parse to object.`); - recommendedExtensions = JSON.parse((await editor.getText()).replace(/\/\*[\s\S]*?\*\/|(?<=[^:])\/\/.*|^\/\/.*/g, '').trim()); - Logger.debug(`recommendedExtensions.recommendations: Get recommendations clear names using map().`); - recommendedExtensions.recommendations = recommendedExtensions.recommendations.map((r: { split: (arg: string) => [any, any]; }) => { - const [publisher, name] = r.split('.'); - return { publisher, name }; - }); - Logger.info(`Recommended extension for this workspace:\n${JSON.stringify(recommendedExtensions.recommendations)}.`); - }); - - test(`Open "Extensions" view section`, async function(): Promise { - Logger.debug(`ActivityBar().getViewControl('Extensions'))?.openView(): open Extensions view.`); - extensionsView = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); - }); - - test(`Let extensions complete installation`, async function(): Promise { - Logger.info(`Time for extensions installation TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT=${TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT}`); - await driverHelper.wait(TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT); - }); - - test(`Check if extensions are installed and enabled`, async function(): Promise { - this.retries(10); - Logger.debug(`ActivityBar().getViewControl('Extensions'))?.openView(): open Extensions view.`); - extensionsView = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); - - Logger.debug(`extensionsView?.getContent().getSections(): get current section.`); - [extensionSection] = await extensionsView?.getContent().getSections() as ExtensionsViewSection[]; - await driverHelper.waitAllPresence(webCheCodeLocators.ExtensionsViewSection.itemTitle, TimeoutConstants.TS_EDITOR_TAB_INTERACTION_TIMEOUT); - - for (const extension of recommendedExtensions.recommendations) { - Logger.info(`Check if ${JSON.stringify(extension)} are installed.`); - - Logger.debug(`extensionSection.findItem(${extension.name}).`); - await extensionSection.findItem(extension.name); - - // check if extension require reload the page - if (await driverHelper.isVisible((webCheCodeLocators.ExtensionsViewSection as any).requireReloadButton)) { - Logger.debug(`Extension require reload the editor. Refreshing the page..`); - await browserTabsUtil.refreshPage(); - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - Logger.debug(`ActivityBar().getViewControl('Extensions'))?.openView(): open Extensions view.`); - extensionsView = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); - Logger.debug(`extensionsView?.getContent().getSections(): get current section.`); - [extensionSection] = await extensionsView?.getContent().getSections() as ExtensionsViewSection[]; - await driverHelper.waitAllPresence(webCheCodeLocators.ExtensionsViewSection.itemTitle, TimeoutConstants.TS_EDITOR_TAB_INTERACTION_TIMEOUT); - Logger.debug(`extensionSection.findItem(${extension.name}).`); - await extensionSection.findItem(extension.name); - } - - Logger.debug(`extensionsView?.getContent().getSections(): switch to marketplace section.`); - const [marketplaceSection]: ExtensionsViewSection[] = await extensionsView?.getContent().getSections() as ExtensionsViewSection[]; - await driverHelper.waitVisibility(webCheCodeLocators.ExtensionsViewSection.items, TimeoutConstants.TS_EDITOR_TAB_INTERACTION_TIMEOUT); - - Logger.debug(`marketplaceSection.getVisibleItems(): get all found items.`); - const allFinedItems: ExtensionsViewItem[] = await marketplaceSection.getVisibleItems(); - - let itemWithRightNameAndPublisher: ExtensionsViewItem | undefined; - for (const item of allFinedItems) { - Logger.debug(`Try to find extension published by ${extension.publisher}.`); - if (await item.getAuthor() === extension.publisher) { - itemWithRightNameAndPublisher = item; - Logger.debug(`Extension was found: ${await itemWithRightNameAndPublisher?.getTitle()}`); - break; - } - if (itemWithRightNameAndPublisher === undefined) { - Logger.error(`Extension with publisher as ${extension.publisher} was not found.`); - } - } - - Logger.debug(`itemWithRightNameAndPublisher?.isInstalled()`); - const isInstalled: boolean = await itemWithRightNameAndPublisher?.isInstalled() as boolean; - - Logger.debug(`itemWithRightNameAndPublisher?.isInstalled(): ${isInstalled}.`); - expect(isInstalled).eqls(true); - - Logger.debug(`itemWithRightNameAndPublisher.manage(): get context menu.`); - const extensionManageMenu: ContextMenu = await (itemWithRightNameAndPublisher as ExtensionsViewItem).manage(); - - Logger.debug(`extensionManageMenu.getItems(): get menu items.`); - const extensionMenuItems: ContextMenuItem[] = await extensionManageMenu.getItems(); - let extensionMenuItemLabels: string = ''; - for (const item of extensionMenuItems) { - Logger.trace(`extensionMenuItems -> item.getLabel(): get menu items names.`); - extensionMenuItemLabels += (await item.getLabel()) + ' '; - } - - Logger.debug(`extensionMenuItemLabels: ${extensionMenuItemLabels}.`); - expect(extensionMenuItemLabels).contains('Disable').and.not.contains('Enable'); - } - }); - - test('Stop the workspace', async function(): Promise { - await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - await browserTabsUtil.closeAllTabsExceptCurrent(); - }); - - test('Delete the workspace', async function(): Promise { - await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - } - - loginTests.logoutFromChe(); +suite(`Check if recommended extensions installed for ${samples}`, function (): void { + let projectSection: ViewSection; + let extensionsView: SideBarView | undefined; + let extensionSection: ExtensionsViewSection; + + const extensionsListFileName: string = 'extensions.json'; + let recommendedExtensions: any = { + recommendations: [] + }; + + loginTests.loginIntoChe(); + + for (const sample of samples) { + test(`Create and open new workspace, stack:${sample}`, async function (): Promise { + await workspaceHandlingTests.createAndOpenWorkspace(sample); + }); + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); + + test('Registering the running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Wait workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + + test('Wait until the project will be imported and accept it as trusted one', async function (): Promise { + [projectSection] = await new SideBarView().getContent().getSections(); + const label: string = BASE_TEST_CONSTANTS.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); + try { + const buttonYesITrustTheAuthors: string = 'Yes, I trust the authors'; + await driverHelper.waitVisibility( + webCheCodeLocators.WelcomeContent.button, + TIMEOUT_CONSTANTS.TS_DIALOG_WINDOW_DEFAULT_TIMEOUT + ); + const trustedProjectDialog: ModalDialog = new ModalDialog(); + Logger.debug(`trustedProjectDialog.pushButton: "${buttonYesITrustTheAuthors}"`); + await trustedProjectDialog.pushButton(buttonYesITrustTheAuthors); + } catch (e) { + Logger.debug(`Welcome modal dialog was not shown: ${e}`); + } + }); + + test(`Get recommended extensions list from ${extensionsListFileName}`, async function (): Promise { + Logger.debug('projectSection.findItem(item))?.select(): expand .vscode folder and open extensions.json.'); + await (await projectSection.findItem('.vscode'))?.select(); + // time to expand project tree + await driverHelper.wait(TIMEOUT_CONSTANTS.TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT); + await (await projectSection.findItem(extensionsListFileName))?.select(); + Logger.debug(`EditorView().openEditor(${extensionsListFileName})`); + const editor: TextEditor = (await new EditorView().openEditor(extensionsListFileName)) as TextEditor; + await driverHelper.waitVisibility(webCheCodeLocators.Editor.inputArea); + Logger.debug('editor.getText(): get recommended extensions as text from editor, delete comments and parse to object.'); + recommendedExtensions = JSON.parse((await editor.getText()).replace(/\/\*[\s\S]*?\*\/|(?<=[^:])\/\/.*|^\/\/.*/g, '').trim()); + Logger.debug('recommendedExtensions.recommendations: Get recommendations clear names using map().'); + recommendedExtensions.recommendations = recommendedExtensions.recommendations.map( + (r: { split: (arg: string) => [any, any] }): { name: any; publisher: any } => { + const [publisher, name] = r.split('.'); + return { publisher, name }; + } + ); + Logger.info(`Recommended extension for this workspace:\n${JSON.stringify(recommendedExtensions.recommendations)}.`); + }); + + test('Open "Extensions" view section', async function (): Promise { + Logger.debug('ActivityBar().getViewControl("Extensions"))?.openView(): open Extensions view.'); + extensionsView = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); + }); + + test('Let extensions complete installation', async function (): Promise { + Logger.info( + `Time for extensions installation TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT=${TIMEOUT_CONSTANTS.TS_COMMON_PLUGIN_TEST_TIMEOUT}` + ); + await driverHelper.wait(TIMEOUT_CONSTANTS.TS_COMMON_PLUGIN_TEST_TIMEOUT); + }); + + test('Check if extensions are installed and enabled', async function (): Promise { + this.retries(10); + Logger.debug('ActivityBar().getViewControl("Extensions"))?.openView(): open Extensions view.'); + extensionsView = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); + + Logger.debug('extensionsView?.getContent().getSections(): get current section.'); + [extensionSection] = (await extensionsView?.getContent().getSections()) as ExtensionsViewSection[]; + await driverHelper.waitAllPresence( + webCheCodeLocators.ExtensionsViewSection.itemTitle, + TIMEOUT_CONSTANTS.TS_EDITOR_TAB_INTERACTION_TIMEOUT + ); + + for (const extension of recommendedExtensions.recommendations) { + Logger.info(`Check if ${JSON.stringify(extension)} are installed.`); + + Logger.debug(`extensionSection.findItem(${extension.name}).`); + await extensionSection.findItem(extension.name); + + // check if extension require reload the page + if (await driverHelper.isVisible((webCheCodeLocators.ExtensionsViewSection as any).requireReloadButton)) { + Logger.debug('Extension require reload the editor. Refreshing the page..'); + await browserTabsUtil.refreshPage(); + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + Logger.debug('ActivityBar().getViewControl("Extensions"))?.openView(): open Extensions view.'); + extensionsView = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); + Logger.debug('extensionsView?.getContent().getSections(): get current section.'); + [extensionSection] = (await extensionsView?.getContent().getSections()) as ExtensionsViewSection[]; + await driverHelper.waitAllPresence( + webCheCodeLocators.ExtensionsViewSection.itemTitle, + TIMEOUT_CONSTANTS.TS_EDITOR_TAB_INTERACTION_TIMEOUT + ); + Logger.debug(`extensionSection.findItem(${extension.name}).`); + await extensionSection.findItem(extension.name); + } + + Logger.debug('extensionsView?.getContent().getSections(): switch to marketplace section.'); + const [marketplaceSection]: ExtensionsViewSection[] = (await extensionsView + ?.getContent() + .getSections()) as ExtensionsViewSection[]; + await driverHelper.waitVisibility( + webCheCodeLocators.ExtensionsViewSection.items, + TIMEOUT_CONSTANTS.TS_EDITOR_TAB_INTERACTION_TIMEOUT + ); + + Logger.debug('marketplaceSection.getVisibleItems(): get all found items.'); + const allFinedItems: ExtensionsViewItem[] = await marketplaceSection.getVisibleItems(); + + let itemWithRightNameAndPublisher: ExtensionsViewItem | undefined; + for (const item of allFinedItems) { + Logger.debug(`Try to find extension published by ${extension.publisher}.`); + if ((await item.getAuthor()) === extension.publisher) { + itemWithRightNameAndPublisher = item; + Logger.debug(`Extension was found: ${await itemWithRightNameAndPublisher?.getTitle()}`); + break; + } + if (itemWithRightNameAndPublisher === undefined) { + Logger.error(`Extension with publisher as ${extension.publisher} was not found.`); + } + } + + Logger.debug('itemWithRightNameAndPublisher?.isInstalled()'); + const isInstalled: boolean = (await itemWithRightNameAndPublisher?.isInstalled()) as boolean; + + Logger.debug(`itemWithRightNameAndPublisher?.isInstalled(): ${isInstalled}.`); + expect(isInstalled).eqls(true); + + Logger.debug('itemWithRightNameAndPublisher.manage(): get context menu.'); + const extensionManageMenu: ContextMenu = await (itemWithRightNameAndPublisher as ExtensionsViewItem).manage(); + + Logger.debug('extensionManageMenu.getItems(): get menu items.'); + const extensionMenuItems: ContextMenuItem[] = await extensionManageMenu.getItems(); + let extensionMenuItemLabels: string = ''; + for (const item of extensionMenuItems) { + Logger.trace('extensionMenuItems -> item.getLabel(): get menu items names.'); + extensionMenuItemLabels += (await item.getLabel()) + ' '; + } + + Logger.debug(`extensionMenuItemLabels: ${extensionMenuItemLabels}.`); + expect(extensionMenuItemLabels).contains('Disable').and.not.contains('Enable'); + } + }); + + test('Stop the workspace', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + test('Delete the workspace', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + } + + loginTests.logoutFromChe(); }); diff --git a/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts index a6a4910aba0..143881a6c4c 100644 --- a/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts +++ b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -12,7 +12,7 @@ import { SideBarView, ViewItem, ViewSection } from 'monaco-page-objects'; import { registerRunningWorkspace } from '../MochaHooks'; import { LoginTests } from '../../tests-library/LoginTests'; import { e2eContainer } from '../../configs/inversify.config'; -import { CLASSES } from '../../configs/inversify.types'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; import { expect } from 'chai'; @@ -21,76 +21,85 @@ import { OcpImportFromGitPage } from '../../pageobjects/openshift/OcpImportFromG import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; import { StringUtil } from '../../utils/StringUtil'; import { OcpApplicationPage } from '../../pageobjects/openshift/OcpApplicationPage'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); +const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); const ocpMainPage: OcpMainPage = e2eContainer.get(CLASSES.OcpMainPage); +const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + let ocpImportPage: OcpImportFromGitPage; let ocpApplicationPage: OcpApplicationPage; const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(); -// works only with no-admin user -suite(`DevConsole Integration`, async function(): Promise { - // test specific data - const gitImportRepo: string = 'https://github.com/crw-qe/summit-lab-spring-music.git'; - const gitImportReference: string = 'pipeline'; - const projectLabel: string = 'app.openshift.io/runtime=spring'; - const projectName: string = 'devconsole-integration-test'; +suite('DevConsole Integration', function (): void { + // test specific data + const gitImportRepo: string = 'https://github.com/crw-qe/summit-lab-spring-music.git'; + const gitImportReference: string = 'pipeline'; + const projectLabel: string = 'app.openshift.io/runtime=spring'; + const projectName: string = 'devconsole-integration-test'; + + suiteSetup('Create new empty project using ocp', function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp(); + kubernetesCommandLineToolsExecutor.createProject(projectName); + }); - suiteSetup('Create new empty project using ocp', async function(): Promise { - kubernetesCommandLineToolsExecutor.loginToOcp(); - kubernetesCommandLineToolsExecutor.createProject(projectName); - }); + loginTests.loginIntoOcpConsole(); - loginTests.loginIntoOcpConsole(); + test('Select test project and Developer role on DevConsole', async function (): Promise { + await ocpMainPage.selectDeveloperRole(); + await ocpMainPage.selectProject(projectName); + }); - test('Select test project and Developer role on DevConsole', async function(): Promise { - await ocpMainPage.selectDeveloperRole(); - await ocpMainPage.selectProject(projectName); - }); + test('Open import from git project page', async function (): Promise { + ocpImportPage = await ocpMainPage.openImportFromGitPage(); + }); - test('Open import from git project page', async function(): Promise { - ocpImportPage = await ocpMainPage.openImportFromGitPage(); - }); + test('Fill and submit import data', async function (): Promise { + ocpApplicationPage = await ocpImportPage.fitAndSubmitConfiguration(gitImportRepo, gitImportReference, projectLabel); + }); - test('Fill and submit import data', async function(): Promise { - ocpApplicationPage = await ocpImportPage.fitAndSubmitConfiguration(gitImportRepo, gitImportReference, projectLabel); - }); + test('Wait until application creates', async function (): Promise { + await ocpApplicationPage.waitApplicationIcon(); + }); - test('Wait until application creates', async function(): Promise { - await ocpApplicationPage.waitApplicationIcon(); - }); + test('Check if application has worked link "Open Source Code"', async function (): Promise { + await ocpApplicationPage.waitAndOpenEditSourceCodeIcon(); + }); - test('Check if application has worked link "Open Source Code"', async function(): Promise { - await ocpApplicationPage.waitAndOpenEditSourceCodeIcon(); - }); + loginTests.loginIntoChe(); - loginTests.loginIntoChe(); + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); - test('Obtain workspace name from workspace loader page', async function(): Promise { - await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - }); + test('Registering the running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - test('Registering the running workspace', async function(): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + test('Check if application source code opens in workspace', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); - test('Check if application source code opens in workspace', async function(): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); + test('Check if project and files imported', async function (): Promise { + const applicationSourceProjectName: string = StringUtil.getProjectNameFromGitUrl(gitImportRepo); + const projectSection: ViewSection = await new SideBarView().getContent().getSection(applicationSourceProjectName); + const isFileImported: ViewItem | undefined = await projectSection.findItem(BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME); + expect(isFileImported).not.eqls(undefined); + }); - test('Check if project and files imported', async function(): Promise { - const applicationSourceProjectName: string = StringUtil.getProjectNameFromGitUrl(gitImportRepo); - const projectSection: ViewSection = await new SideBarView().getContent().getSection(applicationSourceProjectName); - const isFileImported: ViewItem | undefined = await projectSection.findItem(BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME); - expect(isFileImported).not.eqls(undefined); - }); + test('Stop and delete the workspace by API', async function (): Promise { + await browserTabsUtil.closeAllTabsExceptCurrent(); + testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); - loginTests.logoutFromChe(); + loginTests.logoutFromChe(); - suiteTeardown('Delete project using ocp', async function(): Promise { - kubernetesCommandLineToolsExecutor.deleteProject(projectName); - }); + suiteTeardown('Delete project using ocp', function (): void { + kubernetesCommandLineToolsExecutor.deleteProject(projectName); + }); }); diff --git a/tests/e2e/specs/factory/Factory.spec.ts b/tests/e2e/specs/factory/Factory.spec.ts index f58dd35a3b4..71026663ba7 100644 --- a/tests/e2e/specs/factory/Factory.spec.ts +++ b/tests/e2e/specs/factory/Factory.spec.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2021 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -12,18 +12,18 @@ import 'reflect-metadata'; import { e2eContainer } from '../../configs/inversify.config'; import { - ActivityBar, - ContextMenu, - EditorView, - Locators, - ModalDialog, - NewScmView, - SideBarView, - SingleScmProvider, - TextEditor, - ViewControl, - ViewItem, - ViewSection + ActivityBar, + ContextMenu, + EditorView, + Locators, + ModalDialog, + NewScmView, + SideBarView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewItem, + ViewSection } from 'monaco-page-objects'; import { expect } from 'chai'; import { OauthPage } from '../../pageobjects/git-providers/OauthPage'; @@ -37,9 +37,9 @@ import { DriverHelper } from '../../utils/DriverHelper'; import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; import { Logger } from '../../utils/Logger'; import { LoginTests } from '../../tests-library/LoginTests'; -import { OAuthConstants } from '../../constants/OAuthConstants'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; -import { FactoryTestConstants } from '../../constants/FactoryTestConstants'; +import { OAUTH_CONSTANTS } from '../../constants/OAUTH_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { FACTORY_TEST_CONSTANTS } from '../../constants/FACTORY_TEST_CONSTANTS'; const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); @@ -49,154 +49,164 @@ const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; -suite(`Create a workspace via launching a factory from the ${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository`, async function(): Promise { - const oauthPage: OauthPage = new OauthPage(driverHelper); - - let projectSection: ViewSection; - let scmProvider: SingleScmProvider; - let rest: SingleScmProvider[]; - let scmContextMenu: ContextMenu; - - // 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 "${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}"`; - const refreshButtonLabel: string = 'Refresh'; - const pushItemLabel: string = 'Push'; - let testRepoProjectName: string; - - loginTests.loginIntoChe(); - test(`Navigate to the factory URL`, async function(): Promise { - await browserTabsUtil.navigateTo(FactoryTestConstants.TS_SELENIUM_FACTORY_URL()); - }); - - if (OAuthConstants.TS_SELENIUM_GIT_PROVIDER_OAUTH) { - test(`Authorize with a ${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} OAuth`, async function(): Promise { - await oauthPage.login(); - await oauthPage.waitOauthPage(); - await oauthPage.confirmAccess(); - }); - } - - test('Obtain workspace name from workspace loader page', async function(): Promise { - await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - }); - - test('Registering the running workspace', async function(): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - - test('Wait the workspace readiness', async function(): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); - - test('Check if a project folder has been created', async function(): Promise { - testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL); - Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); - projectSection = await new SideBarView().getContent().getSection(testRepoProjectName); - }); - - test('Check if the project files were imported', async function(): Promise { - const label: string = BaseTestConstants.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(): Promise { - 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(): Promise { - 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(): Promise { - 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 are displayed in the source control manager', async function(): Promise { - 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(): Promise { - 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(): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); - Logger.debug(`scmProvider.commitChanges: commit name "Commit ${changesToCommit}"`); - await scmProvider.commitChanges('Commit ' + changesToCommit); - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); - 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(): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(`Push 1 commits to origin/${FactoryTestConstants.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(): Promise { - 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 the workspace', async function(): Promise { - await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - await browserTabsUtil.closeAllTabsExceptCurrent(); - }); - - test('Delete the workspace', async function(): Promise { - await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - - loginTests.logoutFromChe(); -}); +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository`, + function (): void { + const oauthPage: OauthPage = new OauthPage(driverHelper); + + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let rest: SingleScmProvider[]; + let scmContextMenu: ContextMenu; + + // 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 "${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}"`; + const refreshButtonLabel: string = 'Refresh'; + const pushItemLabel: string = 'Push'; + let testRepoProjectName: string; + + loginTests.loginIntoChe(); + test('Navigate to the factory URL', async function (): Promise { + await browserTabsUtil.navigateTo(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_URL()); + }); + + if (OAUTH_CONSTANTS.TS_SELENIUM_GIT_PROVIDER_OAUTH) { + test(`Authorize with a ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} OAuth`, async function (): Promise { + await oauthPage.login(); + await oauthPage.waitOauthPage(); + await oauthPage.confirmAccess(); + }); + } + + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); + + test('Registering the running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Wait the workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + + test('Check if a project folder has been created', async function (): Promise { + testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL); + Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); + projectSection = await new SideBarView().getContent().getSection(testRepoProjectName); + }); + + test('Check if the project files were imported', async function (): Promise { + const label: string = BASE_TEST_CONSTANTS.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 (): Promise { + 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 (): Promise { + 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 (): Promise { + 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: "${JSON.stringify(scmProvider)}, ${rest}"`); + }); + + test('Check if the changes are displayed in the source control manager', async function (): Promise { + 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 (): Promise { + 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 (): Promise { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); + Logger.debug(`scmProvider.commitChanges: commit name "Commit ${changesToCommit}"`); + await scmProvider.commitChanges('Commit ' + changesToCommit); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + 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 (): Promise { + await driverHelper.waitVisibility( + webCheCodeLocators.ScmView.actionConstructor( + `Push 1 commits to origin/${FACTORY_TEST_CONSTANTS.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 (): Promise { + 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 the workspace', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + test('Delete the workspace', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + loginTests.logoutFromChe(); + } +); diff --git a/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts index b4b71cd2243..b8c6b1e18dd 100644 --- a/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts +++ b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2021 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -11,20 +11,20 @@ import 'reflect-metadata'; import { e2eContainer } from '../../configs/inversify.config'; import { - ActivityBar, - ContextMenu, - EditorView, - error, - InputBox, - Locators, - ModalDialog, - NewScmView, - SideBarView, - SingleScmProvider, - TextEditor, - ViewControl, - ViewItem, - ViewSection + ActivityBar, + ContextMenu, + EditorView, + error, + InputBox, + Locators, + ModalDialog, + NewScmView, + SideBarView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewItem, + ViewSection } from 'monaco-page-objects'; import { expect } from 'chai'; import { StringUtil } from '../../utils/StringUtil'; @@ -37,12 +37,12 @@ import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; import { DriverHelper } from '../../utils/DriverHelper'; import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; import { Workspaces } from '../../pageobjects/dashboard/Workspaces'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; import { Logger } from '../../utils/Logger'; import { LoginTests } from '../../tests-library/LoginTests'; -import { FactoryTestConstants, GitProviderType } from '../../constants/FactoryTestConstants'; -import { OAuthConstants } from '../../constants/OAuthConstants'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; +import { FACTORY_TEST_CONSTANTS, GitProviderType } from '../../constants/FACTORY_TEST_CONSTANTS'; +import { OAUTH_CONSTANTS } from '../../constants/OAUTH_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; import WebDriverError = error.WebDriverError; const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); @@ -54,219 +54,234 @@ 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 ${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository without OAuth setup`, async function(): Promise { +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository without OAuth setup`, + function (): void { + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let scmContextMenu: ContextMenu; - let projectSection: ViewSection; - let scmProvider: SingleScmProvider; - let rest: SingleScmProvider[]; - let scmContextMenu: ContextMenu; + // 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 "${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}"`; + const refreshButtonLabel: string = 'Refresh'; + const label: string = BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME; + let testRepoProjectName: string; + const isPrivateRepo: string = FACTORY_TEST_CONSTANTS.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO ? 'private' : 'public'; - // 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 "${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}"`; - const refreshButtonLabel: string = 'Refresh'; - const label: string = BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME; - let testRepoProjectName: string; - const isPrivateRepo: string = FactoryTestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO ? 'private' : 'public'; + loginTests.loginIntoChe(); - loginTests.loginIntoChe(); + test('Get number of previously created workspaces', async function (): Promise { + await dashboard.clickWorkspacesButton(); + await workspaces.waitPage(); + numberOfCreatedWorkspaces = (await workspaces.getAllCreatedWorkspacesNames()).length; + }); - test('Get number of previously created workspaces', async function(): Promise { - await dashboard.clickWorkspacesButton(); - await workspaces.waitPage(); - numberOfCreatedWorkspaces = (await workspaces.getAllCreatedWorkspacesNames()).length; - }); + test(`Navigate to the ${isPrivateRepo} repository factory URL`, async function (): Promise { + await browserTabsUtil.navigateTo(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_URL()); + }); - test(`Navigate to the ${isPrivateRepo} repository factory URL`, async function(): Promise { - await browserTabsUtil.navigateTo(FactoryTestConstants.TS_SELENIUM_FACTORY_URL()); - }); + if (FACTORY_TEST_CONSTANTS.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + test(`Check that workspace cannot be created without OAuth for ${isPrivateRepo} repo`, async function (): Promise { + await dashboard.waitLoader(); + const loaderAlert: string = await dashboard.getLoaderAlert(); + expect(loaderAlert).contains.oneOf([ + 'Cause: Unsupported OAuth provider', + 'Cause: No PersonalAccessTokenFetcher configured' + ]); + }); - if (FactoryTestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + test('Check that workspace was not created', async function (): Promise { + await dashboard.openDashboard(); + await dashboard.clickWorkspacesButton(); + await workspaces.waitPage(); + const allCreatedWorkspacesNames: string[] = await workspaces.getAllCreatedWorkspacesNames(); + expect(allCreatedWorkspacesNames).has.length(numberOfCreatedWorkspaces); + }); - test(`Check that workspace cannot be created without OAuth for ${isPrivateRepo} repo`, async function(): Promise { - await dashboard.waitLoader(); - const loaderAlert: string = await dashboard.getLoaderAlert(); - expect(loaderAlert).contains.oneOf(['Cause: Unsupported OAuth provider', 'Cause: No PersonalAccessTokenFetcher configured']); - }); + loginTests.logoutFromChe(); + } else { + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); - test(`Check that workspace was not created`, async function(): Promise { - await dashboard.openDashboard(); - await dashboard.clickWorkspacesButton(); - await workspaces.waitPage(); - const allCreatedWorkspacesNames: string[] = await workspaces.getAllCreatedWorkspacesNames(); - expect(allCreatedWorkspacesNames).has.length(numberOfCreatedWorkspaces); - }); + test('Registering the running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - loginTests.logoutFromChe(); + test('Wait the workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); - } else { - test('Obtain workspace name from workspace loader page', async function(): Promise { - await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - }); + test('Check if a project folder has been created', async function (): Promise { + testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL); + Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); + projectSection = await new SideBarView().getContent().getSection(testRepoProjectName); + }); - test('Registering the running workspace', async function(): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + test('Accept the project as a trusted one', async function (): Promise { + // 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, + TIMEOUT_CONSTANTS.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 (!FACTORY_TEST_CONSTANTS.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + throw new WebDriverError(e as string); + } + } + }); - test('Wait the workspace readiness', async function(): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); + test('Check if the project files were imported', async function (): Promise { + 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('Check if a project folder has been created', async function(): Promise { - testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL); - Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); - projectSection = await new SideBarView().getContent().getSection(testRepoProjectName); - }); + test('Make changes to the file', async function (): Promise { + 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('Accept the project as a trusted one', async function(): Promise { - // 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 (!FactoryTestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { - throw new WebDriverError(e as string); - } - } - }); + test('Open a source control manager', async function (): Promise { + 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)); + let rest: SingleScmProvider[]; + [scmProvider, ...rest] = await scmView.getProviders(); + Logger.debug(`scmView.getProviders: "${JSON.stringify(scmProvider)}, ${rest}"`); + }); - test('Check if the project files were imported', async function(): Promise { - 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('Check if the changes are displayed in the source control manager', async function (): Promise { + 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('Make changes to the file', async function(): Promise { - 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('Stage the changes', async function (): Promise { + 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('Open a source control manager', async function(): Promise { - 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('Commit the changes', async function (): Promise { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); + Logger.debug(`scmProvider.commitChanges: commit name "Commit ${changesToCommit}"`); + await scmProvider.commitChanges('Commit ' + changesToCommit); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + 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('Check if the changes are displayed in the source control manager', async function(): Promise { - 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('Push the changes', async function (): Promise { + await driverHelper.waitVisibility( + webCheCodeLocators.ScmView.actionConstructor( + `Push 1 commits to origin/${FACTORY_TEST_CONSTANTS.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('Stage the changes', async function(): Promise { - 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'); - }); + if (FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.GITHUB) { + test('Decline GitHub Extension', async function (): Promise { + await driverHelper.waitVisibility(webCheCodeLocators.Dialog.details); + const gitHaExtensionDialog: ModalDialog = new ModalDialog(); + await gitHaExtensionDialog.pushButton('Cancel'); + }); + } - test('Commit the changes', async function(): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); - Logger.debug(`scmProvider.commitChanges: commit name "Commit ${changesToCommit}"`); - await scmProvider.commitChanges('Commit ' + changesToCommit); - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); - 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(): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(`Push 1 commits to origin/${FactoryTestConstants.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 (FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.GITHUB) { - test('Decline GitHub Extension', async function(): Promise { - 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(): Promise { - try { - await driverHelper.waitVisibility(webCheCodeLocators.InputBox.message); - } catch (e) { - Logger.info(`Workspace did not ask credentials before push - ${e}; + test('Insert git credentials which were asked after push', async function (): Promise { + try { + await driverHelper.waitVisibility(webCheCodeLocators.InputBox.message); + } catch (e) { + Logger.info(`Workspace did not ask credentials before push - ${e}; Known issue for github.com - https://issues.redhat.com/browse/CRW-4066, please check if not other git provider. `); - expect(FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER).eqls(GitProviderType.GITHUB); - } - const input: InputBox = new InputBox(); - await input.setText(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_USERNAME); - await input.confirm(); - await driverHelper.wait(timeToRefresh); - await input.setText(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_PASSWORD); - await input.confirm(); - await driverHelper.wait(timeToRefresh); - }); + expect(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER).eqls(GitProviderType.GITHUB); + } + const input: InputBox = new InputBox(); + await input.setText(OAUTH_CONSTANTS.TS_SELENIUM_GIT_PROVIDER_USERNAME); + await input.confirm(); + await driverHelper.wait(timeToRefresh); + await input.setText(OAUTH_CONSTANTS.TS_SELENIUM_GIT_PROVIDER_PASSWORD); + await input.confirm(); + await driverHelper.wait(timeToRefresh); + }); - test('Check if the changes were pushed', async function(): Promise { - 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('Check if the changes were pushed', async function (): Promise { + 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 the workspace', async function(): Promise { - await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - await browserTabsUtil.closeAllTabsExceptCurrent(); - }); + test('Stop the workspace', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); - test('Delete the workspace', async function(): Promise { - await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + test('Delete the workspace', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - loginTests.logoutFromChe(); - } -}); + loginTests.logoutFromChe(); + } + } +); diff --git a/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts index 43d66c238cc..d6627e57113 100644 --- a/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts +++ b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2021 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -11,20 +11,20 @@ import 'reflect-metadata'; import { e2eContainer } from '../../configs/inversify.config'; import { - ActivityBar, - ContextMenu, - EditorView, - error, - InputBox, - Locators, - ModalDialog, - NewScmView, - SideBarView, - SingleScmProvider, - TextEditor, - ViewControl, - ViewItem, - ViewSection + ActivityBar, + ContextMenu, + EditorView, + error, + InputBox, + Locators, + ModalDialog, + NewScmView, + SideBarView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewItem, + ViewSection } from 'monaco-page-objects'; import { expect } from 'chai'; import { registerRunningWorkspace } from '../MochaHooks'; @@ -37,11 +37,11 @@ import { DriverHelper } from '../../utils/DriverHelper'; import { OauthPage } from '../../pageobjects/git-providers/OauthPage'; import { StringUtil } from '../../utils/StringUtil'; import { Logger } from '../../utils/Logger'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; import { LoginTests } from '../../tests-library/LoginTests'; -import { OAuthConstants } from '../../constants/OAuthConstants'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; -import { FactoryTestConstants, GitProviderType } from '../../constants/FactoryTestConstants'; +import { OAUTH_CONSTANTS } from '../../constants/OAUTH_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { FACTORY_TEST_CONSTANTS, GitProviderType } from '../../constants/FACTORY_TEST_CONSTANTS'; import WebDriverError = error.WebDriverError; const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); @@ -51,212 +51,226 @@ const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocato const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -suite(`Create a workspace via launching a factory from the ${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository and deny the access`, async function(): Promise { - const oauthPage: OauthPage = new OauthPage(driverHelper); +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository and deny the access`, + function (): void { + const oauthPage: OauthPage = new OauthPage(driverHelper); - let projectSection: ViewSection; - let scmProvider: SingleScmProvider; - let rest: SingleScmProvider[]; - let scmContextMenu: ContextMenu; + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let scmContextMenu: ContextMenu; - // 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 "${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}"`; - const refreshButtonLabel: string = 'Refresh'; - const pushItemLabel: string = 'Push'; - const label: string = BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME; - let testRepoProjectName: string; - const isPrivateRepo: string = FactoryTestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO ? 'private' : 'public'; + // 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 "${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH}"`; + const refreshButtonLabel: string = 'Refresh'; + const pushItemLabel: string = 'Push'; + const label: string = BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME; + let testRepoProjectName: string; + const isPrivateRepo: string = FACTORY_TEST_CONSTANTS.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO ? 'private' : 'public'; - loginTests.loginIntoChe(); + loginTests.loginIntoChe(); - test(`Navigate to the ${isPrivateRepo} repository factory URL`, async function(): Promise { - await browserTabsUtil.navigateTo(FactoryTestConstants.TS_SELENIUM_FACTORY_URL()); - }); + test(`Navigate to the ${isPrivateRepo} repository factory URL`, async function (): Promise { + await browserTabsUtil.navigateTo(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_URL()); + }); - if (OAuthConstants.TS_SELENIUM_GIT_PROVIDER_OAUTH) { - test(`Authorize with a ${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} OAuth and deny access`, async function(): Promise { - await oauthPage.login(); - await oauthPage.waitOauthPage(); - await oauthPage.denyAccess(); - }); - } + if (OAUTH_CONSTANTS.TS_SELENIUM_GIT_PROVIDER_OAUTH) { + test(`Authorize with a ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} OAuth and deny access`, async function (): Promise { + await oauthPage.login(); + await oauthPage.waitOauthPage(); + await oauthPage.denyAccess(); + }); + } - test('Obtain workspace name from workspace loader page', async function(): Promise { - await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - }); + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); - test('The workspace starts with access deny flag in the url', async function(): Promise { - expect(await driverHelper.getDriver().getCurrentUrl()).contains('&error_code=access_denied'); - }); + test('The workspace starts with access deny flag in the url', async function (): Promise { + expect(await driverHelper.getDriver().getCurrentUrl()).contains('&error_code=access_denied'); + }); - test('Registering the running workspace', async function(): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + test('Registering the running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - test('Wait the workspace readiness', async function(): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); + test('Wait the workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); - test('Check if a project folder has been created', async function(): Promise { - testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL); - Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); - projectSection = await new SideBarView().getContent().getSection(testRepoProjectName); - }); + test('Check if a project folder has been created', async function (): Promise { + testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL); + Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); + projectSection = await new SideBarView().getContent().getSection(testRepoProjectName); + }); - test('Accept the project as a trusted one', async function(): Promise { - // 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 (!FactoryTestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { - throw new WebDriverError(e as string); - } - } - }); + test('Accept the project as a trusted one', async function (): Promise { + // 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, + TIMEOUT_CONSTANTS.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 (!FACTORY_TEST_CONSTANTS.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + throw new WebDriverError(e as string); + } + } + }); - if (FactoryTestConstants.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { - test('Check that project can not be cloned', async function(): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.Dialog.message); - const workspaceDoesNotExistDialog: ModalDialog = new ModalDialog(); - const message: string = await workspaceDoesNotExistDialog.getMessage(); - expect(message).contains('space does not exist'); - }); + if (FACTORY_TEST_CONSTANTS.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + test('Check that project can not be cloned', async function (): Promise { + 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(): Promise { - const isFileImported: ViewItem | undefined = await projectSection.findItem(label); - expect(isFileImported).eqls(undefined); - }); + test('Check that project files were not imported', async function (): Promise { + const isFileImported: ViewItem | undefined = await projectSection.findItem(label); + expect(isFileImported).eqls(undefined); + }); + } else { + test('Check if the project files were imported', async function (): Promise { + 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); + }); - } else { - test('Check if the project files were imported', async function(): Promise { - 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 (): Promise { + 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('Make changes to the file', async function(): Promise { - 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 (): Promise { + 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)); + let rest: SingleScmProvider[]; + [scmProvider, ...rest] = await scmView.getProviders(); + Logger.debug(`scmView.getProviders: "${JSON.stringify(scmProvider)}, ${rest}"`); + }); - test('Open a source control manager', async function(): Promise { - 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 are displayed in the source control manager', async function (): Promise { + 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('Check if the changes are displayed in the source control manager', async function(): Promise { - 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 (): Promise { + 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('Stage the changes', async function(): Promise { - 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 (): Promise { + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); + Logger.debug(`scmProvider.commitChanges: commit name "Commit ${changesToCommit}"`); + await scmProvider.commitChanges('Commit ' + changesToCommit); + await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); + 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('Commit the changes', async function(): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(commitChangesButtonLabel)); - Logger.debug(`scmProvider.commitChanges: commit name "Commit ${changesToCommit}"`); - await scmProvider.commitChanges('Commit ' + changesToCommit); - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.more); - 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 (): Promise { + await driverHelper.waitVisibility( + webCheCodeLocators.ScmView.actionConstructor( + `Push 1 commits to origin/${FACTORY_TEST_CONSTANTS.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('Push the changes', async function(): Promise { - await driverHelper.waitVisibility(webCheCodeLocators.ScmView.actionConstructor(`Push 1 commits to origin/${FactoryTestConstants.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(): Promise { - try { - await driverHelper.waitVisibility(webCheCodeLocators.InputBox.message); - } catch (e) { - Logger.info(`Workspace did not ask credentials before push - ${e}; + test('Insert git credentials which were asked after push', async function (): Promise { + try { + await driverHelper.waitVisibility(webCheCodeLocators.InputBox.message); + } catch (e) { + Logger.info(`Workspace did not ask credentials before push - ${e}; Known issue for github.com - https://issues.redhat.com/browse/CRW-4066, please check if not other git provider. `); - expect(FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER).eqls(GitProviderType.GITHUB); - } - const input: InputBox = new InputBox(); - await input.setText(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_USERNAME); - await input.confirm(); - await driverHelper.wait(timeToRefresh); - await input.setText(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_PASSWORD); - await input.confirm(); - await driverHelper.wait(timeToRefresh); - }); + expect(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER).eqls(GitProviderType.GITHUB); + } + const input: InputBox = new InputBox(); + await input.setText(OAUTH_CONSTANTS.TS_SELENIUM_GIT_PROVIDER_USERNAME); + await input.confirm(); + await driverHelper.wait(timeToRefresh); + await input.setText(OAUTH_CONSTANTS.TS_SELENIUM_GIT_PROVIDER_PASSWORD); + await input.confirm(); + await driverHelper.wait(timeToRefresh); + }); - test('Check if the changes were pushed', async function(): Promise { - 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('Check if the changes were pushed', async function (): Promise { + 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 the workspace', async function(): Promise { - await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - await browserTabsUtil.closeAllTabsExceptCurrent(); - }); + test('Stop the workspace', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); - test('Delete the workspace', async function(): Promise { - await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + test('Delete the workspace', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - loginTests.logoutFromChe(); -}); + loginTests.logoutFromChe(); + } +); diff --git a/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts b/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts index 74deb8ffe3c..82c358a6750 100644 --- a/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts +++ b/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts @@ -1,3 +1,12 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ import { e2eContainer } from '../../configs/inversify.config'; import { assert } from 'chai'; import { CLASSES } from '../../configs/inversify.types'; @@ -13,66 +22,67 @@ const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES. 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; + const { stdout, stderr } = await exec(shellCommandToExecution); + console.log(stdout); + console.error(stderr); + return stdout; } -suite(`Create predefined workspace and check it `, async function(): Promise { - let workspaceName: string = ''; +suite('Create predefined workspace and check it ', function (): void { + let workspaceName: string = ''; - const setEditRightsForUser: string = `oc adm policy add-role-to-user edit user -n ${predefinedNamespaceName}`; - const getDevWorkspaceFromPredefinedNameSpace: string = `oc get dw -n ${predefinedNamespaceName}`; - const deletePredefinedNamespace: string = `oc delete project ${predefinedNamespaceName}`; - const createPredefinedProjectCommand: string = 'cat < { - Logger.info('Test prerequisites:'); - Logger.info(' (1) there is OCP user with username and user password that have been set in the TS_SELENIUM_OCP_USERNAME and TS_SELENIUM_OCP_PASSWORD variables'); - Logger.info(' (2) \'oc\' client installed and logged into test OCP cluster with admin rights.'); + 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 < { + Logger.info('Test prerequisites:'); + Logger.info( + ' (1) there is OCP user with username and user password that have been set in the TS_SELENIUM_OCP_USERNAME and TS_SELENIUM_OCP_PASSWORD variables' + ); + Logger.info(' (2) "oc" client installed and logged into test OCP cluster with admin rights.'); - await runShellScript(createPredefinedProjectCommand); - await runShellScript(setEditRightsForUser); - }); + await runShellScript(createPredefinedProjectCommand); + await runShellScript(setEditRightsForUser); + }); - suiteTeardown(async (): Promise => { - const workspaceName: string = WorkspaceHandlingTests.getWorkspaceName(); - try { - await runShellScript(deletePredefinedNamespace); - } catch (e) { - Logger.error(`Cannot remove the predefined project: ${workspaceName}, please fix it manually: ${e}`); - } - }); + suiteTeardown(async (): Promise => { + 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 - test(`Create and open new workspace, stack:${'Empty Workspace'}`, async function(): Promise { - await workspaceHandlingTests.createAndOpenWorkspace('Empty Workspace'); - }); - test('Obtain workspace name from workspace loader page', async function(): Promise { - await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - }); + loginTests.loginIntoChe(); + // create the Empty workspace using CHE Dashboard + test(`Create and open new workspace, stack:${'Empty Workspace'}`, async function (): Promise { + await workspaceHandlingTests.createAndOpenWorkspace('Empty Workspace'); + }); + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); - // verify that just created workspace with unique name is present in the predefined namespace - test('Validate the created workspace is present in predefined namespace', async function(): Promise { - workspaceName = WorkspaceHandlingTests.getWorkspaceName(); - registerRunningWorkspace(workspaceName); - const ocDevWorkspaceOutput: string = await runShellScript(getDevWorkspaceFromPredefinedNameSpace); - await assert.isTrue(ocDevWorkspaceOutput.includes(workspaceName)); - }); + // verify that just created workspace with unique name is present in the predefined namespace + test('Validate the created workspace is present in predefined namespace', async function (): Promise { + workspaceName = WorkspaceHandlingTests.getWorkspaceName(); + registerRunningWorkspace(workspaceName); + const ocDevWorkspaceOutput: string = await runShellScript(getDevWorkspaceFromPredefinedNameSpace); + assert.isTrue(ocDevWorkspaceOutput.includes(workspaceName)); + }); - loginTests.logoutFromChe(); + loginTests.logoutFromChe(); }); - - diff --git a/tests/e2e/tests-library/LoginTests.ts b/tests/e2e/tests-library/LoginTests.ts index 984f3260cef..2a6fc8534ac 100644 --- a/tests/e2e/tests-library/LoginTests.ts +++ b/tests/e2e/tests-library/LoginTests.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -14,40 +14,42 @@ import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; import { inject, injectable } from 'inversify'; import { Dashboard } from '../pageobjects/dashboard/Dashboard'; import { IOcpLoginPage } from '../pageobjects/login/interfaces/IOcpLoginPage'; -import { BaseTestConstants } from '../constants/BaseTestConstants'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; @injectable() export class LoginTests { - constructor( - @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil, - @inject(TYPES.CheLogin) private readonly productLoginPage: ICheLoginPage, - @inject(TYPES.OcpLogin) private readonly ocpLoginPage: IOcpLoginPage, - @inject(CLASSES.Dashboard) private readonly dashboard: Dashboard) { - } + constructor( + @inject(CLASSES.BrowserTabsUtil) + private readonly browserTabsUtil: BrowserTabsUtil, + @inject(TYPES.CheLogin) + private readonly productLoginPage: ICheLoginPage, + @inject(TYPES.OcpLogin) private readonly ocpLoginPage: IOcpLoginPage, + @inject(CLASSES.Dashboard) private readonly dashboard: Dashboard + ) {} - loginIntoChe(): void { - test('Login', async () => { - if (!(await this.browserTabsUtil.getCurrentUrl()).includes(BaseTestConstants.TS_SELENIUM_BASE_URL)) { - await this.browserTabsUtil.navigateTo(BaseTestConstants.TS_SELENIUM_BASE_URL); - } - await this.productLoginPage.login(); - await this.browserTabsUtil.maximize(); - await this.dashboard.waitStartingPageLoaderDisappearance(); - }); - } + loginIntoChe(): void { + test('Login', async (): Promise => { + if (!(await this.browserTabsUtil.getCurrentUrl()).includes(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL)) { + await this.browserTabsUtil.navigateTo(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL); + } + await this.productLoginPage.login(); + await this.browserTabsUtil.maximize(); + await this.dashboard.waitStartingPageLoaderDisappearance(); + }); + } - loginIntoOcpConsole(): void { - test('Login into ocp console', async () => { - const openshiftConsoleUrl: string = BaseTestConstants.TS_SELENIUM_BASE_URL.replace('devspaces', 'console-openshift-console'); - await this.browserTabsUtil.navigateTo(openshiftConsoleUrl); - await this.ocpLoginPage.login(); - await this.browserTabsUtil.maximize(); - }); - } + loginIntoOcpConsole(): void { + test('Login into ocp console', async (): Promise => { + const openshiftConsoleUrl: string = BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL.replace('devspaces', 'console-openshift-console'); + await this.browserTabsUtil.navigateTo(openshiftConsoleUrl); + this.ocpLoginPage.login(); + await this.browserTabsUtil.maximize(); + }); + } - logoutFromChe(): void { - test('Logout', async () => { - await this.dashboard.logout(); - }); - } + logoutFromChe(): void { + test('Logout', async (): Promise => { + await this.dashboard.logout(); + }); + } } diff --git a/tests/e2e/tests-library/ProjectAndFileTests.ts b/tests/e2e/tests-library/ProjectAndFileTests.ts index 40533db3f40..18a911fbd4c 100644 --- a/tests/e2e/tests-library/ProjectAndFileTests.ts +++ b/tests/e2e/tests-library/ProjectAndFileTests.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -14,24 +14,27 @@ import { By, until } from 'selenium-webdriver'; import { DriverHelper } from '../utils/DriverHelper'; import { CLASSES } from '../configs/inversify.types'; import { Logger } from '../utils/Logger'; -import { TimeoutConstants } from '../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; @injectable() export class ProjectAndFileTests { + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) {} - - async waitWorkspaceReadinessForCheCodeEditor(): Promise { - Logger.debug(`waiting for editor.`); - try { - const start: number = new Date().getTime(); - await this.driverHelper.getDriver().wait(until.elementLocated(By.className('monaco-workbench')), TimeoutConstants.TS_SELENIUM_START_WORKSPACE_TIMEOUT); - const end: number = new Date().getTime(); - Logger.debug(`editor was opened in ${end - start} seconds.`); - } catch (err) { - Logger.error(`waiting for workspace readiness failed: ${err}`); - throw err; - } - } + async waitWorkspaceReadinessForCheCodeEditor(): Promise { + Logger.debug('waiting for editor.'); + try { + const start: number = new Date().getTime(); + await this.driverHelper + .getDriver() + .wait(until.elementLocated(By.className('monaco-workbench')), TIMEOUT_CONSTANTS.TS_SELENIUM_START_WORKSPACE_TIMEOUT); + const end: number = new Date().getTime(); + Logger.debug(`editor was opened in ${end - start} seconds.`); + } catch (err) { + Logger.error(`waiting for workspace readiness failed: ${err}`); + throw err; + } + } } diff --git a/tests/e2e/tests-library/WorkspaceHandlingTests.ts b/tests/e2e/tests-library/WorkspaceHandlingTests.ts index b3b1f207dec..2e41c67f262 100644 --- a/tests/e2e/tests-library/WorkspaceHandlingTests.ts +++ b/tests/e2e/tests-library/WorkspaceHandlingTests.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -16,107 +16,116 @@ import { CreateWorkspace } from '../pageobjects/dashboard/CreateWorkspace'; import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; import { Logger } from '../utils/Logger'; import { ApiUrlResolver } from '../utils/workspace/ApiUrlResolver'; -import { TimeoutConstants } from '../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; import { DriverHelper } from '../utils/DriverHelper'; import { By, error } from 'selenium-webdriver'; @injectable() export class WorkspaceHandlingTests { + private static WORKSPACE_NAME_LOCATOR: By = By.xpath('//h1[contains(.,"Starting workspace ")]'); + private static workspaceName: string = 'undefined'; + private static parentGUID: string; - static getWorkspaceName(): string { - return WorkspaceHandlingTests.workspaceName; - } + constructor( + @inject(CLASSES.Dashboard) private readonly dashboard: Dashboard, + @inject(CLASSES.CreateWorkspace) + private readonly createWorkspace: CreateWorkspace, + @inject(CLASSES.BrowserTabsUtil) + private readonly browserTabsUtil: BrowserTabsUtil, + @inject(CLASSES.ApiUrlResolver) + private readonly apiUrlResolver: ApiUrlResolver, + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - private static WORKSPACE_NAME_LOCATOR: By = By.xpath(`//h1[contains(.,'Starting workspace ')]`); - private static workspaceName: string = 'undefined'; - private static parentGUID: string; + static getWorkspaceName(): string { + return WorkspaceHandlingTests.workspaceName; + } - constructor( - @inject(CLASSES.Dashboard) private readonly dashboard: Dashboard, - @inject(CLASSES.CreateWorkspace) private readonly createWorkspace: CreateWorkspace, - @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil, - @inject(CLASSES.ApiUrlResolver) private readonly apiUrlResolver: ApiUrlResolver, - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) {} + setWindowHandle(guid: string): void { + WorkspaceHandlingTests.parentGUID = guid; + } - setWindowHandle(guid: string): void { - WorkspaceHandlingTests.parentGUID = guid; - } + getWindowHandle(): string { + return WorkspaceHandlingTests.parentGUID; + } - getWindowHandle(): string { - return WorkspaceHandlingTests.parentGUID; - } + async createAndOpenWorkspace(stack: string): Promise { + await this.dashboard.clickWorkspacesButton(); + await this.dashboard.waitPage(); + Logger.debug('fetching user kubernetes namespace, storing auth token by getting workspaces API URL.'); + await this.apiUrlResolver.getWorkspacesApiUrl(); + await this.dashboard.clickCreateWorkspaceButton(); + await this.createWorkspace.waitPage(); + WorkspaceHandlingTests.parentGUID = await this.browserTabsUtil.getCurrentWindowHandle(); + await this.createWorkspace.clickOnSampleNoEditorSelection(stack); + await this.browserTabsUtil.waitAndSwitchToAnotherWindow(WorkspaceHandlingTests.parentGUID, TIMEOUT_CONSTANTS.TS_IDE_LOAD_TIMEOUT); + } - async createAndOpenWorkspace(stack: string): Promise { - await this.dashboard.clickWorkspacesButton(); - await this.dashboard.waitPage(); - Logger.debug(`fetching user kubernetes namespace, storing auth token by getting workspaces API URL.`); - await this.apiUrlResolver.getWorkspacesApiUrl(); - await this.dashboard.clickCreateWorkspaceButton(); - await this.createWorkspace.waitPage(); - WorkspaceHandlingTests.parentGUID = await this.browserTabsUtil.getCurrentWindowHandle(); - await this.createWorkspace.clickOnSampleNoEditorSelection(stack); - await this.browserTabsUtil.waitAndSwitchToAnotherWindow(WorkspaceHandlingTests.parentGUID, TimeoutConstants.TS_IDE_LOAD_TIMEOUT); - } + async createAndOpenWorkspaceFromGitRepository(factoryUrl: string): Promise { + await this.dashboard.waitPage(); + Logger.debug('fetching user kubernetes namespace, storing auth token by getting workspaces API URL.'); + await this.apiUrlResolver.getWorkspacesApiUrl(); + await this.dashboard.clickCreateWorkspaceButton(); + await this.createWorkspace.waitPage(); + WorkspaceHandlingTests.parentGUID = await this.browserTabsUtil.getCurrentWindowHandle(); + await this.createWorkspace.importFromGitUsingUI(factoryUrl); + await this.browserTabsUtil.waitAndSwitchToAnotherWindow(WorkspaceHandlingTests.parentGUID, TIMEOUT_CONSTANTS.TS_IDE_LOAD_TIMEOUT); + } - async createAndOpenWorkspaceFromGitRepository(factoryUrl: string): Promise { - await this.dashboard.waitPage(); - Logger.debug(`fetching user kubernetes namespace, storing auth token by getting workspaces API URL.`); - await this.apiUrlResolver.getWorkspacesApiUrl(); - await this.dashboard.clickCreateWorkspaceButton(); - await this.createWorkspace.waitPage(); - WorkspaceHandlingTests.parentGUID = await this.browserTabsUtil.getCurrentWindowHandle(); - await this.createWorkspace.importFromGitUsingUI(factoryUrl); - await this.browserTabsUtil.waitAndSwitchToAnotherWindow(WorkspaceHandlingTests.parentGUID, TimeoutConstants.TS_IDE_LOAD_TIMEOUT); - } + async obtainWorkspaceNameFromStartingPage(): Promise { + const timeout: number = TIMEOUT_CONSTANTS.TS_IDE_LOAD_TIMEOUT; + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); - async obtainWorkspaceNameFromStartingPage(): Promise { - const timeout: number = TimeoutConstants.TS_IDE_LOAD_TIMEOUT; - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); + for (let i: number = 0; i < attempts; i++) { + try { + const startingWorkspaceLineContent: string = await this.driverHelper + .getDriver() + .findElement(WorkspaceHandlingTests.WORKSPACE_NAME_LOCATOR) + .getText(); + Logger.trace(`obtained starting workspace getText():${startingWorkspaceLineContent}`); + // cutting away leading text + WorkspaceHandlingTests.workspaceName = startingWorkspaceLineContent.substring('Starting workspace '.length).trim(); + Logger.trace(`trimmed workspace name from getText():${WorkspaceHandlingTests.workspaceName}`); + break; + } catch (err) { + if (err instanceof error.StaleElementReferenceError) { + Logger.trace('failed to obtain name from workspace start page, element possibly detached from DOM. Retrying.'); + await this.driverHelper.wait(polling); + continue; + } + if (err instanceof error.NoSuchElementError) { + Logger.trace('failed to obtain name from workspace start page, element not visible yet. Retrying.'); + await this.driverHelper.wait(polling); + continue; + } + Logger.error(`obtaining workspace name failed with an unexpected error:${err}`); + throw err; + } + } + if (WorkspaceHandlingTests.workspaceName !== '' && WorkspaceHandlingTests.workspaceName !== 'undefined') { + Logger.info(`obtained workspace name from workspace loader page: ${WorkspaceHandlingTests.workspaceName}`); + return; + } + Logger.error(`failed to obtain workspace name:${WorkspaceHandlingTests.workspaceName}`); + throw new error.InvalidArgumentError( + `WorkspaceHandlingTests.obtainWorkspaceNameFromStartingPage failed to obtain workspace name:${WorkspaceHandlingTests.workspaceName}` + ); + } - for (let i: number = 0; i < attempts; i++) { - try { - let startingWorkspaceLineContent: string = await this.driverHelper.getDriver().findElement(WorkspaceHandlingTests.WORKSPACE_NAME_LOCATOR).getText(); - Logger.trace(`obtained starting workspace getText():${startingWorkspaceLineContent}`); - // cutting away leading text - WorkspaceHandlingTests.workspaceName = startingWorkspaceLineContent.substring('Starting workspace '.length).trim(); - Logger.trace(`trimmed workspace name from getText():${WorkspaceHandlingTests.workspaceName}`); - break; - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - Logger.trace(`failed to obtain name from workspace start page, element possibly detached from DOM. Retrying.`); - await this.driverHelper.wait(polling); - continue; - } - if (err instanceof error.NoSuchElementError) { - Logger.trace(`failed to obtain name from workspace start page, element not visible yet. Retrying.`); - await this.driverHelper.wait(polling); - continue; - } - Logger.error(`obtaining workspace name failed with an unexpected error:${err}`); - throw err; - } - } - if (WorkspaceHandlingTests.workspaceName !== '' && WorkspaceHandlingTests.workspaceName !== 'undefined') { - Logger.info(`obtained workspace name from workspace loader page: ${WorkspaceHandlingTests.workspaceName}`); - return; - } - Logger.error(`failed to obtain workspace name:${WorkspaceHandlingTests.workspaceName}`); - throw new error.InvalidArgumentError(`WorkspaceHandlingTests.obtainWorkspaceNameFromStartingPage failed to obtain workspace name:${WorkspaceHandlingTests.workspaceName}`); - } + async stopWorkspace(workspaceName: string): Promise { + await this.dashboard.openDashboard(); + await this.dashboard.stopWorkspaceByUI(workspaceName); + } - async stopWorkspace(workspaceName: string): Promise { - await this.dashboard.openDashboard(); - await this.dashboard.stopWorkspaceByUI(workspaceName); - } + async removeWorkspace(workspaceName: string): Promise { + await this.dashboard.openDashboard(); + await this.dashboard.deleteStoppedWorkspaceByUI(workspaceName); + } - async removeWorkspace(workspaceName: string): Promise { - await this.dashboard.openDashboard(); - await this.dashboard.deleteStoppedWorkspaceByUI(workspaceName); - } - - async stopAndRemoveWorkspace(workspaceName: string): Promise { - await this.dashboard.openDashboard(); - await this.dashboard.stopAndRemoveWorkspaceByUI(workspaceName); - } + async stopAndRemoveWorkspace(workspaceName: string): Promise { + await this.dashboard.openDashboard(); + await this.dashboard.stopAndRemoveWorkspaceByUI(workspaceName); + } } diff --git a/tests/e2e/tsconfig.json b/tests/e2e/tsconfig.json index eeedf86192e..e7d4ff8cd2f 100644 --- a/tests/e2e/tsconfig.json +++ b/tests/e2e/tsconfig.json @@ -1,17 +1,17 @@ { - "compilerOptions": { - "skipLibCheck": true, - "target": "es2017", - "module": "commonjs", - "strict": true, - "esModuleInterop": true, - - "outDir": "dist", - "lib": ["es2017", "dom"], - "types": ["reflect-metadata", "@types/mocha", "@types/node"], - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "noImplicitReturns": false, - "sourceMap": true - } + "compilerOptions": { + "skipLibCheck": true, + "target": "es2017", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "outDir": "dist", + "lib": ["es2017", "dom"], + "types": ["reflect-metadata", "@types/mocha", "@types/node"], + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "noImplicitReturns": false, + "sourceMap": true + }, + "include": [".eslintrc.js", "**/*.ts", "**/**/*.ts"] } diff --git a/tests/e2e/tslint.json b/tests/e2e/tslint.json deleted file mode 100644 index ce5a2b93abb..00000000000 --- a/tests/e2e/tslint.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "rules": { - "ban": [ - true, - [ - "_", - "extend" - ], - [ - "_", - "isNull" - ], - [ - "_", - "isDefined" - ] - ], - "class-name": true, - "comment-format": [ - true, - "check-space", - "check-lowercase" - ], - "curly": true, - "eofline": true, - "forin": true, - "indent": [ - true, - "spaces" - ], - "interface-name": true, - "jsdoc-format": true, - "label-position": true, - "max-line-length": [ - false, - 140 - ], - "member-ordering": [ - true, - { - "order": "statics-first" - } - ], - "no-arg": true, - "no-bitwise": true, - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-construct": true, - "no-parameter-properties": false, - "no-debugger": true, - "no-duplicate-variable": true, - "no-empty": true, - "no-eval": true, - "no-string-literal": true, - "no-switch-case-fall-through": true, - "trailing-comma": [ - true, - { - "singleline": "never", - "multiline": { - "objects": "ignore", - "arrays": "always", - "functions": "never", - "typeLiterals": "ignore" - } - } - ], - "no-trailing-whitespace": true, - "no-unused-expression": true, - "no-unused-variable": true, - "no-use-before-declare": true, - "no-var-requires": false, - "one-line": [ - true, - "check-open-brace", - "check-catch", - "check-else", - "check-whitespace" - ], - "quotemark": [ - true, - "single" - ], - "radix": true, - "semicolon": true, - "triple-equals": [ - true, - "allow-null-check" - ], - "typedef": [ - true, - "call-signature", - "member-variable-declaration", - "parameter", - "property-declaration", - "variable-declaration" - ], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "onespace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "use-strict": false, - "variable-name": false, - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type", - "check-module" - ] - } -} diff --git a/tests/e2e/utils/BrowserTabsUtil.ts b/tests/e2e/utils/BrowserTabsUtil.ts index 8051b1fb289..93b304b34da 100644 --- a/tests/e2e/utils/BrowserTabsUtil.ts +++ b/tests/e2e/utils/BrowserTabsUtil.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -12,102 +12,108 @@ import { inject, injectable } from 'inversify'; import { CLASSES } from '../configs/inversify.types'; import { DriverHelper } from './DriverHelper'; import { Logger } from './Logger'; -import { TimeoutConstants } from '../constants/TimeoutConstants'; -import { ChromeDriverConstants } from '../constants/ChromeDriverConstants'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; +import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; @injectable() export class BrowserTabsUtil { - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } - - async switchToWindow(windowHandle: string): Promise { - Logger.debug(); - await this.driverHelper.getDriver().switchTo().window(windowHandle); - } - - async getAllWindowHandles(): Promise { - Logger.debug(); - - return (await this.driverHelper.getDriver()).getAllWindowHandles(); - } - - async getCurrentWindowHandle(): Promise { - Logger.debug(); - - return await this.driverHelper.getDriver().getWindowHandle(); - } - - async navigateTo(url: string): Promise { - Logger.debug(`${url}`); - - await this.driverHelper.getDriver().navigate().to(url); - } - - async navigateAndWaitToUrl(url: string, timeout: number = TimeoutConstants.TS_SELENIUM_WAIT_FOR_URL): Promise { - Logger.trace(`${url}`); - - await this.navigateTo(url); - await this.waitURL(url, timeout); - } - - async waitAndSwitchToAnotherWindow(currentWindowHandle: string, timeout: number): Promise { - Logger.debug(); - - await this.driverHelper.waitUntilTrue(async () => { - const windowHandles: string[] = await this.getAllWindowHandles(); - - return windowHandles.length > 1; - }, timeout); - - const windowHandles: string[] = await this.getAllWindowHandles(); - - for (const windowHandle of windowHandles) { - if (windowHandle !== currentWindowHandle) { - await this.switchToWindow(windowHandle); - } - } - } - - async refreshPage(): Promise { - Logger.debug(); - - await (await this.driverHelper.getDriver()).navigate().refresh(); - } - - async getCurrentUrl(): Promise { - return await this.driverHelper.getDriver().getCurrentUrl(); - } - - async waitURL(expectedUrl: string, timeout: number): Promise { - Logger.trace(`${expectedUrl}`); - - await this.driverHelper.getDriver().wait(async () => { - const currentUrl: string = await this.driverHelper.getDriver().getCurrentUrl(); - const urlEquals: boolean = currentUrl === expectedUrl; - - if (urlEquals) { - return true; - } - }, timeout); - } - - async maximize(): Promise { - Logger.trace(); - if (ChromeDriverConstants.TS_SELENIUM_LAUNCH_FULLSCREEN) { - Logger.debug(`TS_SELENIUM_LAUNCH_FULLSCREEN is set to true, maximizing window.`); - await this.driverHelper.getDriver().manage().window().maximize(); - } - } - - async closeAllTabsExceptCurrent(): Promise { - Logger.trace(); - const allTabsHandles: string[] = await this.getAllWindowHandles(); - const currentTabHandle: string = await this.getCurrentWindowHandle(); - allTabsHandles.splice(allTabsHandles.indexOf(currentTabHandle), 1); - - for (const tabHandle of allTabsHandles) { - await this.switchToWindow(tabHandle); - await this.driverHelper.getDriver().close(); - } - await this.switchToWindow(currentTabHandle); - } + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async switchToWindow(windowHandle: string): Promise { + Logger.debug(); + await this.driverHelper.getDriver().switchTo().window(windowHandle); + } + + async getAllWindowHandles(): Promise { + Logger.debug(); + + return (await this.driverHelper.getDriver()).getAllWindowHandles(); + } + + async getCurrentWindowHandle(): Promise { + Logger.debug(); + + return await this.driverHelper.getDriver().getWindowHandle(); + } + + async navigateTo(url: string): Promise { + Logger.debug(`${url}`); + + await this.driverHelper.getDriver().navigate().to(url); + } + + async navigateAndWaitToUrl(url: string, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL): Promise { + Logger.trace(`${url}`); + + await this.navigateTo(url); + await this.waitURL(url, timeout); + } + + async waitAndSwitchToAnotherWindow(currentWindowHandle: string, timeout: number): Promise { + Logger.debug(); + + await this.driverHelper.waitUntilTrue(async (): Promise => { + const windowHandles: string[] = await this.getAllWindowHandles(); + + return windowHandles.length > 1; + }, timeout); + + const windowHandles: string[] = await this.getAllWindowHandles(); + + for (const windowHandle of windowHandles) { + if (windowHandle !== currentWindowHandle) { + await this.switchToWindow(windowHandle); + } + } + } + + async refreshPage(): Promise { + Logger.debug(); + + await (await this.driverHelper.getDriver()).navigate().refresh(); + } + + async getCurrentUrl(): Promise { + return await this.driverHelper.getDriver().getCurrentUrl(); + } + + async waitURL(expectedUrl: string, timeout: number): Promise { + Logger.trace(`${expectedUrl}`); + try { + await this.driverHelper.getDriver().wait(async (): Promise => { + const currentUrl: string = await this.driverHelper.getDriver().getCurrentUrl(); + const urlEquals: boolean = currentUrl === expectedUrl; + + if (urlEquals) { + return true; + } + }, timeout); + } catch (e) { + throw e; + } + } + + async maximize(): Promise { + Logger.trace(); + if (CHROME_DRIVER_CONSTANTS.TS_SELENIUM_LAUNCH_FULLSCREEN) { + Logger.debug('TS_SELENIUM_LAUNCH_FULLSCREEN is set to true, maximizing window.'); + await this.driverHelper.getDriver().manage().window().maximize(); + } + } + + async closeAllTabsExceptCurrent(): Promise { + Logger.trace(); + const allTabsHandles: string[] = await this.getAllWindowHandles(); + const currentTabHandle: string = await this.getCurrentWindowHandle(); + allTabsHandles.splice(allTabsHandles.indexOf(currentTabHandle), 1); + + for (const tabHandle of allTabsHandles) { + await this.switchToWindow(tabHandle); + await this.driverHelper.getDriver().close(); + } + await this.switchToWindow(currentTabHandle); + } } diff --git a/tests/e2e/utils/CheReporter.ts b/tests/e2e/utils/CheReporter.ts index fd297742e47..4bc9a4c01b9 100644 --- a/tests/e2e/utils/CheReporter.ts +++ b/tests/e2e/utils/CheReporter.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -15,15 +15,15 @@ import * as rm from 'rimraf'; import { logging } from 'selenium-webdriver'; import { DriverHelper } from './DriverHelper'; import { ScreenCatcher } from './ScreenCatcher'; -import { TimeoutConstants } from '../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; import { Logger } from './Logger'; import { e2eContainer } from '../configs/inversify.config'; import { StringUtil } from './StringUtil'; -import { BaseTestConstants } from '../constants/BaseTestConstants'; -import { ChromeDriverConstants } from '../constants/ChromeDriverConstants'; -import { OAuthConstants } from '../constants/OAuthConstants'; -import { ReporterConstants } from '../constants/ReporterConstants'; -import { PluginsTestConstants } from '../constants/PluginsTestConstants'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; +import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; +import { OAUTH_CONSTANTS } from '../constants/OAUTH_CONSTANTS'; +import { REPORTER_CONSTANTS } from '../constants/REPORTER_CONSTANTS'; +import { PLUGIN_TEST_CONSTANTS } from '../constants/PLUGIN_TEST_CONSTANTS'; const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); const screenCatcher: ScreenCatcher = e2eContainer.get(CLASSES.ScreenCatcher); @@ -31,153 +31,149 @@ let methodIndex: number = 0; let deleteScreencast: boolean = true; class CheReporter extends mocha.reporters.Spec { + constructor(runner: mocha.Runner, options: mocha.MochaOptions) { + super(runner, options); - constructor(runner: mocha.Runner, options: mocha.MochaOptions) { - super(runner, options); + runner.on('start', (): void => { + let launchInformation: string = `################## Launch Information ################## - runner.on('start', async (): Promise => { - let launchInformation: string = - `################## Launch Information ################## + TS_SELENIUM_BASE_URL: ${BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL} + TS_SELENIUM_HEADLESS: ${CHROME_DRIVER_CONSTANTS.TS_SELENIUM_HEADLESS} + TS_SELENIUM_OCP_USERNAME: ${OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME} + TS_SELENIUM_EDITOR: ${BASE_TEST_CONSTANTS.TS_SELENIUM_EDITOR} - TS_SELENIUM_BASE_URL: ${BaseTestConstants.TS_SELENIUM_BASE_URL} - TS_SELENIUM_HEADLESS: ${ChromeDriverConstants.TS_SELENIUM_HEADLESS} - TS_SELENIUM_OCP_USERNAME: ${OAuthConstants.TS_SELENIUM_OCP_USERNAME} - TS_SELENIUM_EDITOR: ${BaseTestConstants.TS_SELENIUM_EDITOR} + TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME: ${BASE_TEST_CONSTANTS.TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME} + TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS: ${REPORTER_CONSTANTS.TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS} + TS_SELENIUM_REPORT_FOLDER: ${REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER} + TS_SELENIUM_EXECUTION_SCREENCAST: ${REPORTER_CONSTANTS.TS_SELENIUM_EXECUTION_SCREENCAST} + DELETE_SCREENCAST_IF_TEST_PASS: ${REPORTER_CONSTANTS.DELETE_SCREENCAST_IF_TEST_PASS} + TS_SELENIUM_REMOTE_DRIVER_URL: ${CHROME_DRIVER_CONSTANTS.TS_SELENIUM_REMOTE_DRIVER_URL} + DELETE_WORKSPACE_ON_FAILED_TEST: ${BASE_TEST_CONSTANTS.DELETE_WORKSPACE_ON_FAILED_TEST} + TS_SELENIUM_LOG_LEVEL: ${REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL} + TS_SELENIUM_LAUNCH_FULLSCREEN: ${CHROME_DRIVER_CONSTANTS.TS_SELENIUM_LAUNCH_FULLSCREEN} - TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME: ${BaseTestConstants.TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME} - TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS: ${ReporterConstants.TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS} - TS_SELENIUM_REPORT_FOLDER: ${ReporterConstants.TS_SELENIUM_REPORT_FOLDER} - TS_SELENIUM_EXECUTION_SCREENCAST: ${ReporterConstants.TS_SELENIUM_EXECUTION_SCREENCAST} - DELETE_SCREENCAST_IF_TEST_PASS: ${ReporterConstants.DELETE_SCREENCAST_IF_TEST_PASS} - TS_SELENIUM_REMOTE_DRIVER_URL: ${ChromeDriverConstants.TS_SELENIUM_REMOTE_DRIVER_URL} - DELETE_WORKSPACE_ON_FAILED_TEST: ${BaseTestConstants.DELETE_WORKSPACE_ON_FAILED_TEST} - TS_SELENIUM_LOG_LEVEL: ${ReporterConstants.TS_SELENIUM_LOG_LEVEL} - TS_SELENIUM_LAUNCH_FULLSCREEN: ${ChromeDriverConstants.TS_SELENIUM_LAUNCH_FULLSCREEN} + TS_COMMON_DASHBOARD_WAIT_TIMEOUT: ${TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT} + TS_SELENIUM_START_WORKSPACE_TIMEOUT: ${TIMEOUT_CONSTANTS.TS_SELENIUM_START_WORKSPACE_TIMEOUT} + TS_WAIT_LOADER_PRESENCE_TIMEOUT: ${TIMEOUT_CONSTANTS.TS_WAIT_LOADER_PRESENCE_TIMEOUT} - TS_COMMON_DASHBOARD_WAIT_TIMEOUT: ${TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT} - TS_SELENIUM_START_WORKSPACE_TIMEOUT: ${TimeoutConstants.TS_SELENIUM_START_WORKSPACE_TIMEOUT} - TS_WAIT_LOADER_PRESENCE_TIMEOUT: ${TimeoutConstants.TS_WAIT_LOADER_PRESENCE_TIMEOUT} - - TS_SAMPLE_LIST: ${PluginsTestConstants.TS_SAMPLE_LIST} + TS_SAMPLE_LIST: ${PLUGIN_TEST_CONSTANTS.TS_SAMPLE_LIST} ${process.env.MOCHA_DIRECTORY ? 'MOCHA_DIRECTORY: ' + process.env.MOCHA_DIRECTORY : 'MOCHA_DRIRECTORY is not set'} ${process.env.USERSTORY ? 'USERSTORY: ' + process.env.USERSTORY : 'USERSTORY is not set'} `; - if (ReporterConstants.TS_SELENIUM_PRINT_TIMEOUT_VARIABLES) { - launchInformation += `\n TS_SELENIUM_PRINT_TIMEOUT_VARIABLES is set to true: \n`; - Object.entries(TimeoutConstants).forEach( - ([key, value]) => launchInformation += `\n ${key}: ${value}`); - } else { - launchInformation += `\n to output timeout variables, set TS_SELENIUM_PRINT_TIMEOUT_VARIABLES to true`; - } - - launchInformation += `\n ######################################################## \n`; - - console.log(launchInformation); - - rm.sync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER); - }); - - runner.on('test', async function(test: mocha.Test): Promise { - if (!ReporterConstants.TS_SELENIUM_EXECUTION_SCREENCAST) { - return; - } - - methodIndex = methodIndex + 1; - const currentMethodIndex: number = methodIndex; - let iterationIndex: number = 1; - - while (!(test.state === 'passed' || test.state === 'failed')) { - await screenCatcher.catchMethodScreen(test.title, currentMethodIndex, iterationIndex); - iterationIndex = iterationIndex + 1; - - await driverHelper.wait(ReporterConstants.TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS); - } - }); - - runner.on('pass', async (test: mocha.Test) => { - if (BaseTestConstants.TS_LOAD_TESTS) { - const loadTestReportFolder: string = ReporterConstants.TS_SELENIUM_LOAD_TEST_REPORT_FOLDER; - const loadTestFilePath: string = loadTestReportFolder + '/load-test-results.txt'; - const report: string = test.title + ': ' + test.duration + '\r'; - if (!fs.existsSync(loadTestReportFolder)) { - fs.mkdirSync(loadTestReportFolder); - } - fs.appendFileSync(loadTestFilePath, report); - } - }); - - runner.on('end', async function(): Promise { - // ensure that fired events done - await driverHelper.wait(5000); - - // close driver - await driverHelper.getDriver().quit(); - - // delete screencast folder if conditions matched - if (deleteScreencast && ReporterConstants.DELETE_SCREENCAST_IF_TEST_PASS) { - rm.sync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER); - } - }); - - runner.on('fail', async function(test: mocha.Test): Promise { - Logger.error(`CheReporter runner.on.fail: ${test.fullTitle()} failed after ${test.duration}ms`); - // raise flag for keeping the screencast - deleteScreencast = false; - - Logger.trace(`FullTitle:${test.fullTitle()}`); - const testFullTitle: string = StringUtil.sanitizeTitle(test.fullTitle()); - Logger.trace(`FullTitleSanitized:${testFullTitle}`); - Logger.trace(`TestTitle:${test.title}`); - const testTitle: string = StringUtil.sanitizeTitle(test.title); - Logger.trace(`TestTitleSanitized:${testTitle}`); - - const testReportDirPath: string = `${ReporterConstants.TS_SELENIUM_REPORT_FOLDER}/${testFullTitle}`; - const screenshotFileName: string = `${testReportDirPath}/screenshot-${testTitle}.png`; - const pageSourceFileName: string = `${testReportDirPath}/pagesource-${testTitle}.html`; - const browserLogsFileName: string = `${testReportDirPath}/browserlogs-${testTitle}.txt`; - - // create reporter dir if not exist - const reportDirExists: boolean = fs.existsSync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER); - - if (!reportDirExists) { - fs.mkdirSync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER); - } - - // create dir for failed test report if not exist - const testReportDirExists: boolean = fs.existsSync(testReportDirPath); - - if (!testReportDirExists) { - fs.mkdirSync(testReportDirPath); - } - - // take screenshot and write to file - const screenshot: string = await driverHelper.getDriver().takeScreenshot(); - const screenshotStream: WriteStream = fs.createWriteStream(screenshotFileName); - screenshotStream.write(Buffer.from(screenshot, 'base64')); - screenshotStream.end(); - - // take page source and write to file - const pageSource: string = await driverHelper.getDriver().getPageSource(); - const pageSourceStream: WriteStream = fs.createWriteStream(pageSourceFileName); - pageSourceStream.write(Buffer.from(pageSource)); - pageSourceStream.end(); - - // take browser console logs and write to file - const browserLogsEntries: logging.Entry[] = await driverHelper.getDriver().manage().logs().get('browser'); - let browserLogs: string = ''; - - browserLogsEntries.forEach(log => { - browserLogs += `\"${log.level}\" \"${log.type}\" \"${log.message}\"\n`; - }); - - const browserLogsStream: WriteStream = fs.createWriteStream(browserLogsFileName); - browserLogsStream.write(Buffer.from(browserLogs)); - browserLogsStream.end(); - - }); - } + if (REPORTER_CONSTANTS.TS_SELENIUM_PRINT_TIMEOUT_VARIABLES) { + launchInformation += '\n TS_SELENIUM_PRINT_TIMEOUT_VARIABLES is set to true: \n'; + Object.entries(TIMEOUT_CONSTANTS).forEach(([key, value]): string => (launchInformation += `\n ${key}: ${value}`)); + } else { + launchInformation += '\n to output timeout variables, set TS_SELENIUM_PRINT_TIMEOUT_VARIABLES to true'; + } + + launchInformation += '\n ######################################################## \n'; + + console.log(launchInformation); + + rm.sync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + }); + + runner.on('test', async function (test: mocha.Test): Promise { + if (!REPORTER_CONSTANTS.TS_SELENIUM_EXECUTION_SCREENCAST) { + return; + } + + methodIndex = methodIndex + 1; + const currentMethodIndex: number = methodIndex; + let iterationIndex: number = 1; + + while (!(test.state === 'passed' || test.state === 'failed')) { + await screenCatcher.catchMethodScreen(test.title, currentMethodIndex, iterationIndex); + iterationIndex = iterationIndex + 1; + + await driverHelper.wait(REPORTER_CONSTANTS.TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS); + } + }); + + runner.on('pass', (test: mocha.Test): void => { + if (BASE_TEST_CONSTANTS.TS_LOAD_TESTS) { + const loadTestReportFolder: string = REPORTER_CONSTANTS.TS_SELENIUM_LOAD_TEST_REPORT_FOLDER; + const loadTestFilePath: string = loadTestReportFolder + '/load-test-results.txt'; + const report: string = test.title + ': ' + test.duration + '\r'; + if (!fs.existsSync(loadTestReportFolder)) { + fs.mkdirSync(loadTestReportFolder); + } + fs.appendFileSync(loadTestFilePath, report); + } + }); + + runner.on('end', async (): Promise => { + // ensure that fired events done + await driverHelper.wait(5000); + + // close driver + await driverHelper.getDriver().quit(); + + // delete screencast folder if conditions matched + if (deleteScreencast && REPORTER_CONSTANTS.DELETE_SCREENCAST_IF_TEST_PASS) { + rm.sync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + } + }); + + runner.on('fail', async function (test: mocha.Test): Promise { + Logger.error(`CheReporter runner.on.fail: ${test.fullTitle()} failed after ${test.duration}ms`); + // raise flag for keeping the screencast + deleteScreencast = false; + + Logger.trace(`FullTitle:${test.fullTitle()}`); + const testFullTitle: string = StringUtil.sanitizeTitle(test.fullTitle()); + Logger.trace(`FullTitleSanitized:${testFullTitle}`); + Logger.trace(`TestTitle:${test.title}`); + const testTitle: string = StringUtil.sanitizeTitle(test.title); + Logger.trace(`TestTitleSanitized:${testTitle}`); + + const testReportDirPath: string = `${REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER}/${testFullTitle}`; + const screenshotFileName: string = `${testReportDirPath}/screenshot-${testTitle}.png`; + const pageSourceFileName: string = `${testReportDirPath}/pagesource-${testTitle}.html`; + const browserLogsFileName: string = `${testReportDirPath}/browserlogs-${testTitle}.txt`; + + // create reporter dir if not exist + const reportDirExists: boolean = fs.existsSync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + + if (!reportDirExists) { + fs.mkdirSync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + } + + // create dir for failed test report if not exist + const testReportDirExists: boolean = fs.existsSync(testReportDirPath); + + if (!testReportDirExists) { + fs.mkdirSync(testReportDirPath); + } + + // take screenshot and write to file + const screenshot: string = await driverHelper.getDriver().takeScreenshot(); + const screenshotStream: WriteStream = fs.createWriteStream(screenshotFileName); + screenshotStream.write(Buffer.from(screenshot, 'base64')); + screenshotStream.end(); + + // take page source and write to file + const pageSource: string = await driverHelper.getDriver().getPageSource(); + const pageSourceStream: WriteStream = fs.createWriteStream(pageSourceFileName); + pageSourceStream.write(Buffer.from(pageSource)); + pageSourceStream.end(); + + // take browser console logs and write to file + const browserLogsEntries: logging.Entry[] = await driverHelper.getDriver().manage().logs().get('browser'); + let browserLogs: string = ''; + + browserLogsEntries.forEach((log): void => { + browserLogs += `\"${log.level}\" \"${log.type}\" \"${log.message}\"\n`; + }); + + const browserLogsStream: WriteStream = fs.createWriteStream(browserLogsFileName); + browserLogsStream.write(Buffer.from(browserLogs)); + browserLogsStream.end(); + }); + } } export = CheReporter; diff --git a/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts b/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts index 544b5326d37..59fe1dc5812 100644 --- a/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts +++ b/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts @@ -1,3 +1,12 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ import { Main as Generator } from '@eclipse-che/che-devworkspace-generator/lib/main'; import { DevfileContext } from '@eclipse-che/che-devworkspace-generator/lib/api/devfile-context'; import { V1alpha2DevWorkspaceTemplate } from '@devfile/api'; @@ -5,7 +14,7 @@ import YAML from 'yaml'; import * as axios from 'axios'; import { Logger } from './Logger'; import { ShellExecutor } from './ShellExecutor'; -import { APITestConstants } from '../constants/APITestConstants'; +import { API_TEST_CONSTANTS } from '../constants/API_TEST_CONSTANTS'; /** * to see more about IContextParams and generateDevfileContext(params) check README.md in "@eclipse-che/che-devworkspace-generator; @@ -13,71 +22,71 @@ import { APITestConstants } from '../constants/APITestConstants'; */ interface IContextParams { - devfilePath?: string | undefined; - devfileUrl?: string | undefined; - devfileContent?: string | undefined; - outputFile?: string | undefined; - editorPath?: string | undefined; - editorContent?: string | undefined; - editorEntry?: string | undefined; - pluginRegistryUrl?: string | undefined; - projects?: { - name: string; - location: string; - }[]; - injectDefaultComponent?: string | undefined; - defaultComponentImage?: string | undefined; + devfilePath?: string | undefined; + devfileUrl?: string | undefined; + devfileContent?: string | undefined; + outputFile?: string | undefined; + editorPath?: string | undefined; + editorContent?: string | undefined; + editorEntry?: string | undefined; + pluginRegistryUrl?: string | undefined; + projects?: { + name: string; + location: string; + }[]; + injectDefaultComponent?: string | undefined; + defaultComponentImage?: string | undefined; } export class DevWorkspaceConfigurationHelper { - private generator: Generator = new Generator(); - private readonly params: IContextParams; + private generator: Generator = new Generator(); + private readonly params: IContextParams; - constructor(params: IContextParams) { - // check if all undefined - if (!(params.editorPath || params.editorEntry || params.editorContent)) { - params.editorEntry = 'che-incubator/che-code/latest'; - } - // check if one or both has value - if (APITestConstants.TS_API_TEST_UDI_IMAGE || params.defaultComponentImage) { - params.injectDefaultComponent = 'true'; - // check if not explicitly passed than assign value from the constants - if (!params.defaultComponentImage) { - params.defaultComponentImage = APITestConstants.TS_API_TEST_UDI_IMAGE; - } - } - // assign value from the constants if not explicitly passed - if (APITestConstants.TS_API_TEST_PLUGIN_REGISTRY_URL && !params.pluginRegistryUrl) { - params.pluginRegistryUrl = APITestConstants.TS_API_TEST_PLUGIN_REGISTRY_URL; - } - if (APITestConstants.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI && !params.editorContent) { - params.editorContent = ShellExecutor.curl(APITestConstants.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI).stdout; - } - this.params = params; - } + constructor(params: IContextParams) { + // check if all undefined + if (!(params.editorPath || params.editorEntry || params.editorContent)) { + params.editorEntry = 'che-incubator/che-code/latest'; + } + // check if one or both has value + if (API_TEST_CONSTANTS.TS_API_TEST_UDI_IMAGE || params.defaultComponentImage) { + params.injectDefaultComponent = 'true'; + // check if not explicitly passed than assign value from the constants + if (!params.defaultComponentImage) { + params.defaultComponentImage = API_TEST_CONSTANTS.TS_API_TEST_UDI_IMAGE; + } + } + // assign value from the constants if not explicitly passed + if (API_TEST_CONSTANTS.TS_API_TEST_PLUGIN_REGISTRY_URL && !params.pluginRegistryUrl) { + params.pluginRegistryUrl = API_TEST_CONSTANTS.TS_API_TEST_PLUGIN_REGISTRY_URL; + } + if (API_TEST_CONSTANTS.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI && !params.editorContent) { + params.editorContent = ShellExecutor.curl(API_TEST_CONSTANTS.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI).stdout; + } + this.params = params; + } - async generateDevfileContext(): Promise { - Logger.debug(); - if (!this.params.projects) { - this.params.projects = []; - } - return await this.generator.generateDevfileContext( - { - ...this.params, - projects: this.params.projects - }, - axios.default as any - ); - } + async generateDevfileContext(): Promise { + Logger.debug(); + if (!this.params.projects) { + this.params.projects = []; + } + return await this.generator.generateDevfileContext( + { + ...this.params, + projects: this.params.projects + }, + axios.default as any + ); + } - // write templates and then DevWorkspace in a single file - async getDevWorkspaceConfigurationYamlAsString(context: DevfileContext): Promise { - Logger.debug(); - const allContentArray: any[] = context.devWorkspaceTemplates.map( - (template: V1alpha2DevWorkspaceTemplate) => YAML.stringify(template) - ); - allContentArray.push(YAML.stringify(context.devWorkspace)); + // write templates and then DevWorkspace in a single file + getDevWorkspaceConfigurationYamlAsString(context: DevfileContext): string { + Logger.debug(); + const allContentArray: any[] = context.devWorkspaceTemplates.map((template: V1alpha2DevWorkspaceTemplate): string => + YAML.stringify(template) + ); + allContentArray.push(YAML.stringify(context.devWorkspace)); - return allContentArray.join('---\n'); - } + return allContentArray.join('---\n'); + } } diff --git a/tests/e2e/utils/DevfilesRegistryHelper.ts b/tests/e2e/utils/DevfilesRegistryHelper.ts index 8a6170ce4e0..3e8731e7e07 100644 --- a/tests/e2e/utils/DevfilesRegistryHelper.ts +++ b/tests/e2e/utils/DevfilesRegistryHelper.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2023 Red Hat, Inc. +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -10,68 +10,77 @@ import axios, { AxiosResponse } from 'axios'; import { Logger } from './Logger'; import YAML from 'yaml'; -import { APITestConstants, SupportedDevfilesRegistries } from '../constants/APITestConstants'; +import { API_TEST_CONSTANTS, SUPPORTED_DEVFILE_REGISTRIES } from '../constants/API_TEST_CONSTANTS'; export class DevfilesRegistryHelper { + async getInbuiltDevfilesRegistryContent(): Promise { + Logger.debug(); + return await this.getContent(SUPPORTED_DEVFILE_REGISTRIES.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL()); + } - async getInbuiltDevfilesRegistryContent(): Promise { - Logger.debug(); - return await this.getContent(SupportedDevfilesRegistries.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL()); - } + async getGitHubCheDevfileRegistryContent(): Promise { + Logger.debug(); + return await this.getContent(SUPPORTED_DEVFILE_REGISTRIES.GIT_HUB_CHE_DEVFILE_REGISTRY_URL); + } - async getGitHubCheDevfileRegistryContent(): Promise { - Logger.debug(); - return await this.getContent(SupportedDevfilesRegistries.GIT_HUB_CHE_DEVFILE_REGISTRY_URL); - } + async collectPathsToDevfilesFromRegistry(): Promise { + Logger.debug(); + const devfileSamples: object[] = []; + const sampleNames: string[] = []; + switch (API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL()) { + case SUPPORTED_DEVFILE_REGISTRIES.GIT_HUB_CHE_DEVFILE_REGISTRY_URL: + { + const content: any[any] = await this.getGitHubCheDevfileRegistryContent(); + content.forEach((e: any): void => { + if (e.name[0] !== '.') { + sampleNames.push(e.name); + } + }); - async collectPathsToDevfilesFromRegistry(): Promise { - Logger.debug(); - const devfileSamples: object[] = []; - const sampleNames: string[] = []; - switch (APITestConstants.TS_API_ACCEPTANCE_TEST_REGISTRY_URL()) { - case (SupportedDevfilesRegistries.GIT_HUB_CHE_DEVFILE_REGISTRY_URL): { - const content: any[any] = await this.getGitHubCheDevfileRegistryContent(); - content.forEach((e: any) => { - if (e.name[0] !== '.') { sampleNames.push(e.name); } - }); + for (const sample of sampleNames) { + const sampleEndpoint: string = `${SUPPORTED_DEVFILE_REGISTRIES.GIT_HUB_CHE_DEVFILE_REGISTRY_URL}${sample}/meta.yaml`; + const sampleEndpointContent: AxiosResponse = await this.getContent(sampleEndpoint); + const decodedFileContent: string = Buffer.from((sampleEndpointContent as any).content, 'base64').toString(); + const metaYamlContent: any = YAML.parse(decodedFileContent); + devfileSamples.push({ + name: sample, + link: metaYamlContent.links.v2 + }); + } + Logger.debug(`samples list: ${JSON.stringify(devfileSamples)}`); + } + break; + case SUPPORTED_DEVFILE_REGISTRIES.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL(): + { + const content: any[any] = await this.getInbuiltDevfilesRegistryContent(); - for (const sample of sampleNames) { - const sampleEndpoint: string = `${SupportedDevfilesRegistries.GIT_HUB_CHE_DEVFILE_REGISTRY_URL}${sample}/meta.yaml`; - const sampleEndpointContent: AxiosResponse = await this.getContent(sampleEndpoint); - const decodedFileContent: string = Buffer.from((sampleEndpointContent as any).content, 'base64').toString(); - const metaYamlContent: any = YAML.parse(decodedFileContent); - devfileSamples.push({ name: sample, link: metaYamlContent.links.v2 }); - } - Logger.debug(`samples list: ${JSON.stringify(devfileSamples)}`); - } - break; - case (SupportedDevfilesRegistries.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL()): { - const content: any[any] = await this.getInbuiltDevfilesRegistryContent(); + for (const sample of content) { + devfileSamples.push({ + name: sample.displayName, + link: sample.links.v2 + }); + } + Logger.debug(`samples list: ${JSON.stringify(devfileSamples)}`); + } + break; + default: { + Logger.error(`unsupported registry url - ${API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL()}\n + supported registries: ${JSON.stringify(SUPPORTED_DEVFILE_REGISTRIES)}`); + } + } + return devfileSamples; + } - for (const sample of content) { - devfileSamples.push({ name: sample.displayName, link: sample.links.v2 }); - } - Logger.debug(`samples list: ${JSON.stringify(devfileSamples)}`); - } - break; - default: { - Logger.error(`unsupported registry url - ${APITestConstants.TS_API_ACCEPTANCE_TEST_REGISTRY_URL()}\n - supported registries: ${JSON.stringify(SupportedDevfilesRegistries)}`); - } - } - return devfileSamples; - } + private async getContent(url: string, headers?: object): Promise { + Logger.debug(`${url}`); - private async getContent(url: string, headers?: object): Promise { - Logger.debug(`${url}`); - - let response: AxiosResponse | undefined; - try { - response = await axios.get(url, headers); - } catch (error) { - Logger.error(`${error} + ${url}`); - throw error; - } - return response?.data; - } + let response: AxiosResponse | undefined; + try { + response = await axios.get(url, headers); + } catch (error) { + Logger.error(`${error} + ${url}`); + throw error; + } + return response?.data; + } } diff --git a/tests/e2e/utils/DriverHelper.ts b/tests/e2e/utils/DriverHelper.ts index eb8f641f2ca..94c29310c08 100644 --- a/tests/e2e/utils/DriverHelper.ts +++ b/tests/e2e/utils/DriverHelper.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,705 +13,731 @@ import { TYPES } from '../configs/inversify.types'; import { Actions, By, error, ThenableWebDriver, until, WebElement } from 'selenium-webdriver'; import 'reflect-metadata'; import { Logger } from './Logger'; -import { TimeoutConstants } from '../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; @injectable() export class DriverHelper { - private readonly driver: ThenableWebDriver; - - constructor(@inject(TYPES.Driver) driver: IDriver) { - this.driver = driver.get() as ThenableWebDriver; - } - - getAction(): Actions { - Logger.trace(); - - return this.driver.actions(); - } - - async isVisible(locator: By): Promise { - Logger.trace(`${locator}`); - - try { - const element: WebElement = await this.driver.findElement(locator); - return await element.isDisplayed(); - } catch { - return false; - } - } - - async wait(milliseconds: number): Promise { - Logger.trace(`(${milliseconds} milliseconds)`); - - await this.driver.sleep(milliseconds); - } - - async refreshPage(): Promise { - Logger.trace(); - - await this.driver.navigate().refresh(); - } - - async waitVisibilityBoolean(locator: By, - attempts: number = TimeoutConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, - polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING): Promise { - - Logger.trace(`${locator}`); - - for (let i: number = 0; i < attempts; i++) { - const isVisible: boolean = await this.isVisible(locator); - - if (isVisible) { - return true; - } - - await this.wait(polling); - } - - return false; - } - - async waitDisappearanceBoolean(locator: By, - attempts: number = TimeoutConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, - polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING): Promise { - - Logger.trace(`${locator}`); - - for (let i: number = 0; i < attempts; i++) { - const isVisible: boolean = await this.isVisible(locator); - - if (!isVisible) { - return true; - } - - await this.wait(polling); - } - - return false; - } - - async waitVisibility(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator}`); - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.driver.wait(until.elementLocated(elementLocator), polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - if (attempts !== 1) { // waitVisibility was spamming other methods when the number of attempts was 1 - only show message if attempts > 1 - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - } - continue; - } - - if (err instanceof error.NoSuchWindowError) { // sometimes waitVisibility fails with NoSuchWindowError when the check is run too soon before the page loads - Logger.trace(`failed with NoSuchWindow exception. Attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - const visibleWebElement: WebElement = await this.driver.wait(until.elementIsVisible(element), polling); - Logger.trace('element is located and is visible.'); - return visibleWebElement; - } catch (err) { - if (err instanceof error.TimeoutError) { - if (attempts !== 1) { // waitVisibility was spamming other methods when the number of attempts was 1 - only show message if attempts > 1 - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - } - continue; - } - - if (err instanceof error.StaleElementReferenceError) { - Logger.debug(`stale element error - ${err}`); - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum visibility checking attempts for '${elementLocator}' element, timeouted after ${timeout}`); - } - - async waitPresence(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator}`); - - for (let i: number = 0; i < attempts; i++) { - try { - return await this.driver.wait(until.elementLocated(elementLocator), polling); - } catch (err) { - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum presence checking attempts, problems with 'StaleElementReferenceError' of '${elementLocator}' element`); - } - - async waitAllPresence(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise> { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator}`); - - for (let i: number = 0; i < attempts; i++) { - try { - return await this.driver.wait(until.elementsLocated(elementLocator), polling); - } catch (err) { - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum presence checkings attempts, problems with 'StaleElementReferenceError' of '${elementLocator}' element`); - } - - async waitAllVisibility(locators: Array, timeout: number): Promise { - Logger.trace(`${locators}`); - - for (const elementLocator of locators) { - await this.waitVisibility(elementLocator, timeout); - } - } - - async waitDisappearance(elementLocator: By, - attempts: number = TimeoutConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, - polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING): Promise { - - Logger.trace(`${elementLocator}`); - - const isDisappeared: boolean = await this.waitDisappearanceBoolean(elementLocator, attempts, polling); - - if (!isDisappeared) { - throw new error.TimeoutError(`Waiting attempts exceeded, element '${elementLocator}' is still visible`); - } - } - - async waitDisappearanceWithTimeout(elementLocator: By, timeout: number): Promise { - Logger.trace(`${elementLocator}`); - - await this.getDriver().wait(async () => { - const isVisible: boolean = await this.isVisible(elementLocator); - - if (!isVisible) { - return true; - } - }, timeout); - } - - async waitAllDisappearance(locators: Array, - attemptsPerLocator: number = TimeoutConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, - pollingPerLocator: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING): Promise { - - Logger.trace(`${locators}`); - - for (const elementLocator of locators) { - await this.waitDisappearance(elementLocator, attemptsPerLocator, pollingPerLocator); - } - } - - async waitAndClick(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator}`); - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.waitVisibility(elementLocator, polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - await element.click(); - return; - } catch (err) { - function isElementClickInterceptedOnLastAttempt(err: Error, i: number): boolean { - return err instanceof error.ElementClickInterceptedError && i === attempts - 1; - } - - if (err instanceof error.StaleElementReferenceError || err instanceof error.ElementClickInterceptedError) { - Logger.debug(`${elementLocator} - ${err}`); - await this.wait(polling); - continue; - } - - if (isElementClickInterceptedOnLastAttempt(err, i)) { - Logger.debug(`element is not clickable, try to perform pointer click`); - await this.getAction() - .move({ - origin: await this.waitPresence(elementLocator) - }) - .click() - .perform(); - return; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum clicking attempts, the '${elementLocator}' element is not clickable`); - } - - async waitAndGetElementAttribute(elementLocator: By, attribute: string, - timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator} attribute: '${attribute}'`); - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.waitVisibility(elementLocator, polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - return await element.getAttribute(attribute); - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum gettin of the '${attribute}' attribute attempts, from the '${elementLocator}' element`); - } - - async waitAndGetCssValue(elementLocator: By, cssAttribute: string, - timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator} cssAttribute: ${cssAttribute}`); - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.waitVisibility(elementLocator, polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - return await element.getCssValue(cssAttribute); - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum gettin of the '${cssAttribute}' css attribute attempts, from the '${elementLocator}' element`); - } - - async waitAttributeValue(elementLocator: By, - attribute: string, - expectedValue: string, - timeout: number): Promise { - - Logger.trace(`${elementLocator}`); - - await this.driver.wait(async () => { - const attributeValue: string = await this.waitAndGetElementAttribute(elementLocator, attribute, timeout); - - return expectedValue === attributeValue; - }, - timeout, - `The '${attribute}' attribute value doesn't match with expected value '${expectedValue}'`); - } - - async type(elementLocator: By, text: string, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - if (elementLocator.toString().toLocaleLowerCase().includes('password')) { - Logger.trace(`${elementLocator} text: ***`); - } else { - Logger.trace(`${elementLocator} text: ${text}`); - } - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.waitVisibility(elementLocator, polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - await element.sendKeys(text); - return; - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum typing attempts, to the '${elementLocator}' element`); - } - - async typeToInvisible(elementLocator: By, text: string, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator} text: ${text}`); - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.waitPresence(elementLocator, polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - await element.sendKeys(text); - return; - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum typing attempts, to the '${elementLocator}' element`); - } - - async clear(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator}`); - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.waitVisibility(elementLocator, polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - await element.clear(); - return; - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum clearing attempts, to the '${elementLocator}' element`); - } - - async clearInvisible(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator}`); - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.waitPresence(elementLocator, polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - await element.clear(); - return; - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum clearing attempts, to the '${elementLocator}' element`); - } - - async enterValue(elementLocator: By, text: string, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - if (elementLocator.toString().toLocaleLowerCase().includes('password')) { - Logger.trace(`${elementLocator} text: ***`); - } else { - Logger.trace(`${elementLocator} text: ${text}`); - } - - await this.waitVisibility(elementLocator, timeout); - await this.clear(elementLocator); - await this.waitAttributeValue(elementLocator, 'value', '', timeout); - await this.type(elementLocator, text, timeout); - await this.waitAttributeValue(elementLocator, 'value', text, timeout); - } - - async waitAndSwitchToFrame(iframeLocator: By, timeout: number): Promise { - Logger.trace(`${iframeLocator}`); - - await this.driver.wait(until.ableToSwitchToFrame(iframeLocator), timeout); - } - - async waitAndGetText(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator}`); - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.waitVisibility(elementLocator, polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - return await element.getText(); - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum text obtaining attempts, from the '${elementLocator}' element`); - } - - async waitAndGetValue(elementLocator: By, timeout: number): Promise { - Logger.trace(`${elementLocator}`); - - return await this.waitAndGetElementAttribute(elementLocator, 'value', timeout); - } - - async waitUntilTrue(callback: any, timeout: number): Promise { - Logger.trace(); - - await this.driver.wait(callback, timeout); - } - - async scrollTo(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - const polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - const attempts: number = Math.ceil(timeout / polling); - - Logger.trace(`${elementLocator}`); - - for (let i: number = 0; i < attempts; i++) { - let element: WebElement; - try { - element = await this.waitPresence(elementLocator, polling); - } catch (err) { - if (i >= attempts - 1) { - Logger.error(`failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - - try { - await this.getDriver() - .executeScript('arguments[0].scrollIntoView(true);', element); - return; - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum mouse move attempts, for the '${elementLocator}' element`); - } - - async scrollToAndClick(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - await this.scrollTo(elementLocator, timeout); - await this.waitAndClick(elementLocator, timeout); - } - - async scrollToAndEnterValue(elementLocator: By, value: string, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { - await this.scrollTo(elementLocator, timeout); - await this.enterValue(elementLocator, value, timeout); - } - - // method is useful to debug page object elements - async highLightElement(element: WebElement): Promise { - await this.getDriver().executeScript('arguments[0].style.border=\'2px solid red\'', element); - } - - getDriver(): ThenableWebDriver { - Logger.trace(); - - return this.driver; - } + private readonly driver: ThenableWebDriver; + + constructor(@inject(TYPES.Driver) driver: IDriver) { + this.driver = driver.get(); + } + + getAction(): Actions { + Logger.trace(); + + return this.driver.actions(); + } + + async isVisible(locator: By): Promise { + Logger.trace(`${locator}`); + + try { + const element: WebElement = await this.driver.findElement(locator); + return await element.isDisplayed(); + } catch { + return false; + } + } + + async wait(milliseconds: number): Promise { + Logger.trace(`(${milliseconds} milliseconds)`); + + await this.driver.sleep(milliseconds); + } + + async refreshPage(): Promise { + Logger.trace(); + + await this.driver.navigate().refresh(); + } + + async waitVisibilityBoolean( + locator: By, + attempts: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, + polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING + ): Promise { + Logger.trace(`${locator}`); + + for (let i: number = 0; i < attempts; i++) { + const isVisible: boolean = await this.isVisible(locator); + + if (isVisible) { + return true; + } + + await this.wait(polling); + } + + return false; + } + + async waitDisappearanceBoolean( + locator: By, + attempts: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, + polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING + ): Promise { + Logger.trace(`${locator}`); + + for (let i: number = 0; i < attempts; i++) { + const isVisible: boolean = await this.isVisible(locator); + + if (!isVisible) { + return true; + } + + await this.wait(polling); + } + + return false; + } + + async waitVisibility(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator}`); + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.driver.wait(until.elementLocated(elementLocator), polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + if (attempts !== 1) { + // waitVisibility was spamming other methods when the number of attempts was 1 - only show message if attempts > 1 + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + } + continue; + } + + if (err instanceof error.NoSuchWindowError) { + // sometimes waitVisibility fails with NoSuchWindowError when the check is run too soon before the page loads + Logger.trace(`failed with NoSuchWindow exception. Attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + const visibleWebElement: WebElement = await this.driver.wait(until.elementIsVisible(element), polling); + Logger.trace('element is located and is visible.'); + return visibleWebElement; + } catch (err) { + if (err instanceof error.TimeoutError) { + if (attempts !== 1) { + // waitVisibility was spamming other methods when the number of attempts was 1 - only show message if attempts > 1 + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + } + continue; + } + + if (err instanceof error.StaleElementReferenceError) { + Logger.debug(`stale element error - ${JSON.stringify(err)}`); + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError( + `Exceeded maximum visibility checking attempts for '${elementLocator}' element, timeouted after ${timeout}` + ); + } + + async waitPresence(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator}`); + + for (let i: number = 0; i < attempts; i++) { + try { + return await this.driver.wait(until.elementLocated(elementLocator), polling); + } catch (err) { + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError( + `Exceeded maximum presence checking attempts, problems with 'StaleElementReferenceError' of '${elementLocator}' element` + ); + } + + async waitAllPresence( + elementLocator: By, + timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM + ): Promise> { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator}`); + + for (let i: number = 0; i < attempts; i++) { + try { + return await this.driver.wait(until.elementsLocated(elementLocator), polling); + } catch (err) { + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError( + `Exceeded maximum presence checkings attempts, problems with 'StaleElementReferenceError' of '${elementLocator}' element` + ); + } + + async waitAllVisibility(locators: Array, timeout: number): Promise { + Logger.trace(`${locators}`); + + for (const elementLocator of locators) { + await this.waitVisibility(elementLocator, timeout); + } + } + + async waitDisappearance( + elementLocator: By, + attempts: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, + polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING + ): Promise { + Logger.trace(`${elementLocator}`); + + const isDisappeared: boolean = await this.waitDisappearanceBoolean(elementLocator, attempts, polling); + + if (!isDisappeared) { + throw new error.TimeoutError(`Waiting attempts exceeded, element '${elementLocator}' is still visible`); + } + } + + async waitAllDisappearance( + locators: Array, + attemptsPerLocator: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, + pollingPerLocator: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING + ): Promise { + Logger.trace(`${locators}`); + try { + for (const elementLocator of locators) { + await this.waitDisappearance(elementLocator, attemptsPerLocator, pollingPerLocator); + } + } catch (e) { + throw e; + } + } + + async waitAndClick(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator}`); + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.waitVisibility(elementLocator, polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + await element.click(); + return; + } catch (err) { + function isElementClickInterceptedOnLastAttempt(err: Error, i: number): boolean { + return err instanceof error.ElementClickInterceptedError && i === attempts - 1; + } + + if (err instanceof error.StaleElementReferenceError || err instanceof error.ElementClickInterceptedError) { + Logger.debug(`${elementLocator} - ${JSON.stringify(err)}`); + await this.wait(polling); + continue; + } + + if (isElementClickInterceptedOnLastAttempt(err, i)) { + Logger.debug('element is not clickable, try to perform pointer click'); + await this.getAction() + .move({ + origin: await this.waitPresence(elementLocator) + }) + .click() + .perform(); + return; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError(`Exceeded maximum clicking attempts, the '${elementLocator}' element is not clickable`); + } + + async waitAndGetElementAttribute( + elementLocator: By, + attribute: string, + timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM + ): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator} attribute: '${attribute}'`); + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.waitVisibility(elementLocator, polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + return await element.getAttribute(attribute); + } catch (err) { + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError( + `Exceeded maximum gettin of the '${attribute}' attribute attempts, from the '${elementLocator}' element` + ); + } + + async waitAndGetCssValue( + elementLocator: By, + cssAttribute: string, + timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM + ): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator} cssAttribute: ${cssAttribute}`); + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.waitVisibility(elementLocator, polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + return await element.getCssValue(cssAttribute); + } catch (err) { + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError( + `Exceeded maximum gettin of the '${cssAttribute}' css attribute attempts, from the '${elementLocator}' element` + ); + } + + async waitAttributeValue(elementLocator: By, attribute: string, expectedValue: string, timeout: number): Promise { + Logger.trace(`${elementLocator}`); + + await this.driver.wait( + async (): Promise => { + const attributeValue: string = await this.waitAndGetElementAttribute(elementLocator, attribute, timeout); + + return expectedValue === attributeValue; + }, + timeout, + `The '${attribute}' attribute value doesn't match with expected value '${expectedValue}'` + ); + } + + async type(elementLocator: By, text: string, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + if (elementLocator.toString().toLocaleLowerCase().includes('password')) { + Logger.trace(`${elementLocator} text: ***`); + } else { + Logger.trace(`${elementLocator} text: ${text}`); + } + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.waitVisibility(elementLocator, polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + await element.sendKeys(text); + return; + } catch (err) { + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError(`Exceeded maximum typing attempts, to the '${elementLocator}' element`); + } + + async typeToInvisible( + elementLocator: By, + text: string, + timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM + ): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator} text: ${text}`); + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.waitPresence(elementLocator, polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + await element.sendKeys(text); + return; + } catch (err) { + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError(`Exceeded maximum typing attempts, to the '${elementLocator}' element`); + } + + async clear(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator}`); + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.waitVisibility(elementLocator, polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + await element.clear(); + return; + } catch (err) { + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError(`Exceeded maximum clearing attempts, to the '${elementLocator}' element`); + } + + async clearInvisible(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator}`); + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.waitPresence(elementLocator, polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + await element.clear(); + return; + } catch (err) { + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError(`Exceeded maximum clearing attempts, to the '${elementLocator}' element`); + } + + async enterValue( + elementLocator: By, + text: string, + timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM + ): Promise { + if (elementLocator.toString().toLocaleLowerCase().includes('password')) { + Logger.trace(`${elementLocator} text: ***`); + } else { + Logger.trace(`${elementLocator} text: ${text}`); + } + + await this.waitVisibility(elementLocator, timeout); + await this.clear(elementLocator); + await this.waitAttributeValue(elementLocator, 'value', '', timeout); + await this.type(elementLocator, text, timeout); + await this.waitAttributeValue(elementLocator, 'value', text, timeout); + } + + async waitAndSwitchToFrame(iframeLocator: By, timeout: number): Promise { + Logger.trace(`${iframeLocator}`); + + await this.driver.wait(until.ableToSwitchToFrame(iframeLocator), timeout); + } + + async waitAndGetText(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator}`); + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.waitVisibility(elementLocator, polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + return await element.getText(); + } catch (err) { + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError(`Exceeded maximum text obtaining attempts, from the '${elementLocator}' element`); + } + + async waitAndGetValue(elementLocator: By, timeout: number): Promise { + Logger.trace(`${elementLocator}`); + + return await this.waitAndGetElementAttribute(elementLocator, 'value', timeout); + } + + async waitUntilTrue(callback: any, timeout: number): Promise { + Logger.trace(); + + await this.driver.wait(callback, timeout); + } + + async scrollTo(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + Logger.trace(`${elementLocator}`); + + for (let i: number = 0; i < attempts; i++) { + let element: WebElement; + try { + element = await this.waitPresence(elementLocator, polling); + } catch (err) { + if (i >= attempts - 1) { + Logger.error(`failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`polling timed out attempt #${i + 1}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + + try { + await this.getDriver().executeScript('arguments[0].scrollIntoView(true);', element); + return; + } catch (err) { + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError(`Exceeded maximum mouse move attempts, for the '${elementLocator}' element`); + } + + async scrollToAndClick(elementLocator: By, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + await this.scrollTo(elementLocator, timeout); + await this.waitAndClick(elementLocator, timeout); + } + + async scrollToAndEnterValue( + elementLocator: By, + value: string, + timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM + ): Promise { + await this.scrollTo(elementLocator, timeout); + await this.enterValue(elementLocator, value, timeout); + } + + // method is useful to debug page object elements + async highLightElement(element: WebElement): Promise { + await this.getDriver().executeScript('arguments[0].style.border="2px solid red"', element); + } + + getDriver(): ThenableWebDriver { + Logger.trace(); + + return this.driver; + } } diff --git a/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts b/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts index 41d5dd623e2..5e81c96d474 100644 --- a/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts +++ b/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts @@ -1,190 +1,206 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ import { echo, exec, ShellString } from 'shelljs'; import { Logger } from './Logger'; import { ShellExecutor } from './ShellExecutor'; import * as path from 'path'; -import { APITestConstants, KubernetesCommandLineTool } from '../constants/APITestConstants'; -import { BaseTestConstants } from '../constants/BaseTestConstants'; -import { OAuthConstants } from '../constants/OAuthConstants'; +import { API_TEST_CONSTANTS, KubernetesCommandLineTool } from '../constants/API_TEST_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; +import { OAUTH_CONSTANTS } from '../constants/OAUTH_CONSTANTS'; export class KubernetesCommandLineToolsExecutor extends ShellExecutor { - private static container: string; - private static pod: string; - private readonly namespace: string; - private readonly workspaceName: string | undefined; - private readonly KUBERNETES_COMMAND_LINE_TOOL: string = - APITestConstants.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL; - - constructor(_workspaceName?: string, _namespace?: string) { - super(); - this.workspaceName = _workspaceName; - this.namespace = this.setNamespace(_namespace); - } - - get getWorkspaceName(): string { - return this.workspaceName; - } - - get getNamespace(): string { - return this.namespace; - } - - // login to Openshift cluster with username and password - loginToOcp(): void { - if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.OC) { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - login to the "OC" client.`); - const url: string = this.getServerUrl(); - if (this.isUserLoggedIn()) { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - user already logged`); - } else { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - login ${url}, ${OAuthConstants.TS_SELENIUM_OCP_USERNAME}`); - exec(`oc login --server=${url} -u=${OAuthConstants.TS_SELENIUM_OCP_USERNAME} -p=${OAuthConstants.TS_SELENIUM_OCP_PASSWORD} --insecure-skip-tls-verify`); - } - } else { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - doesn't support login command`); - } - } - - getContainerName(): string { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - get container name.`); - const output: ShellString = ShellExecutor.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} get ${KubernetesCommandLineToolsExecutor.pod} -o jsonpath='{.spec.containers[*].name}' -n ${this.namespace}`); - echo('\n'); - return output.stderr ? output.stderr : output.stdout; - } - - getWorkspacePodName(): string { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - get workspace pod name.`); - const output: ShellString = ShellExecutor.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} get pod -l controller.devfile.io/devworkspace_name=${this.workspaceName} -n ${this.namespace} -o name`); - return output.stderr ? output.stderr : output.stdout.replace('\n', ''); - } - - deleteDevWorkspace(): void { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - delete '${this.workspaceName}' workspace`); - ShellExecutor.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} patch dw ${this.workspaceName} -n ${this.namespace} -p '{ "metadata": { "finalizers": null }}' --type merge || true`); - ShellExecutor.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} delete dw ${this.workspaceName} -n ${this.namespace} || true`); - ShellExecutor.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} delete dwt ${BaseTestConstants.TS_SELENIUM_EDITOR}-${this.workspaceName} -n ${this.namespace} || true`); - } - - applyAndWaitDevWorkspace(yamlConfiguration: string): ShellString { - if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.KUBECTL) { - this.createNamespace(); - } - this.applyYamlConfigurationAsStringOutput(yamlConfiguration); - return this.waitDevWorkspace(); - } - - executeCommand( - commandToExecute: string, - container: string = KubernetesCommandLineToolsExecutor.container): ShellString { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL}`); - return ShellExecutor.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} exec -i ${KubernetesCommandLineToolsExecutor.pod} -n ${this.namespace} -c ${container} -- sh -c '${commandToExecute}'`); - } - - applyYamlConfigurationAsStringOutput(yamlConfiguration: string): ShellString { - Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL}`); - return ShellExecutor.execWithLog(`cat <this.workspaceName; + } + + get getNamespace(): string { + return this.namespace; + } + + // login to Openshift cluster with username and password + loginToOcp(): void { + if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.OC) { + Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - login to the "OC" client.`); + const url: string = this.getServerUrl(); + if (this.isUserLoggedIn()) { + Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - user already logged`); + } else { + Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - login ${url}, ${OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME}`); + exec( + `oc login --server=${url} -u=${OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME} -p=${OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD} --insecure-skip-tls-verify` + ); + } + } else { + Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - doesn't support login command`); + } + } + + getContainerName(): string { + Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - get container name.`); + const output: ShellString = ShellExecutor.execWithLog( + `${this.KUBERNETES_COMMAND_LINE_TOOL} get ${KubernetesCommandLineToolsExecutor.pod} -o jsonpath='{.spec.containers[*].name}' -n ${this.namespace}` + ); + echo('\n'); + return output.stderr ? output.stderr : output.stdout; + } + + getWorkspacePodName(): string { + Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - get workspace pod name.`); + const output: ShellString = ShellExecutor.execWithLog( + `${this.KUBERNETES_COMMAND_LINE_TOOL} get pod -l controller.devfile.io/devworkspace_name=${this.workspaceName} -n ${this.namespace} -o name` + ); + return output.stderr ? output.stderr : output.stdout.replace('\n', ''); + } + + deleteDevWorkspace(): void { + Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL} - delete '${this.workspaceName}' workspace`); + ShellExecutor.execWithLog( + `${this.KUBERNETES_COMMAND_LINE_TOOL} patch dw ${this.workspaceName} -n ${this.namespace} -p '{ "metadata": { "finalizers": null }}' --type merge || true` + ); + ShellExecutor.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} delete dw ${this.workspaceName} -n ${this.namespace} || true`); + ShellExecutor.execWithLog( + `${this.KUBERNETES_COMMAND_LINE_TOOL} delete dwt ${BASE_TEST_CONSTANTS.TS_SELENIUM_EDITOR}-${this.workspaceName} -n ${this.namespace} || true` + ); + } + + applyAndWaitDevWorkspace(yamlConfiguration: string): ShellString { + if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.KUBECTL) { + this.createNamespace(); + } + this.applyYamlConfigurationAsStringOutput(yamlConfiguration); + return this.waitDevWorkspace(); + } + + executeCommand(commandToExecute: string, container: string = KubernetesCommandLineToolsExecutor.container): ShellString { + Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL}`); + return ShellExecutor.execWithLog( + `${this.KUBERNETES_COMMAND_LINE_TOOL} exec -i ${KubernetesCommandLineToolsExecutor.pod} -n ${this.namespace} -c ${container} -- sh -c '${commandToExecute}'` + ); + } + + applyYamlConfigurationAsStringOutput(yamlConfiguration: string): ShellString { + Logger.debug(`${this.KUBERNETES_COMMAND_LINE_TOOL}`); + return ShellExecutor.execWithLog( + `cat < "functionName" - return stack[3].includes('. "functionName" + return stack[3].includes('. { - const executionScreenCastDir: string = `${ReporterConstants.TS_SELENIUM_REPORT_FOLDER}/executionScreencast`; - const executionScreenCastErrorsDir: string = `${ReporterConstants.TS_SELENIUM_REPORT_FOLDER}/executionScreencastErrors`; - const formattedMethodIndex: string = new Intl.NumberFormat('en-us', { minimumIntegerDigits: 3 }).format(methodIndex); - const formattedScreenshotIndex: string = new Intl.NumberFormat('en-us', { minimumIntegerDigits: 5 }).format(screenshotIndex).replace(/,/g, ''); + async catchMethodScreen(methodName: string, methodIndex: number, screenshotIndex: number): Promise { + const executionScreenCastDir: string = `${REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER}/executionScreencast`; + const executionScreenCastErrorsDir: string = `${REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER}/executionScreencastErrors`; + const formattedMethodIndex: string = new Intl.NumberFormat('en-us', { + minimumIntegerDigits: 3 + }).format(methodIndex); + const formattedScreenshotIndex: string = new Intl.NumberFormat('en-us', { minimumIntegerDigits: 5 }) + .format(screenshotIndex) + .replace(/,/g, ''); - if (!fs.existsSync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER)) { - fs.mkdirSync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER); - } + if (!fs.existsSync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER)) { + fs.mkdirSync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + } - if (!fs.existsSync(executionScreenCastDir)) { - fs.mkdirSync(executionScreenCastDir); - } + if (!fs.existsSync(executionScreenCastDir)) { + fs.mkdirSync(executionScreenCastDir); + } - const date: Date = new Date(); - const timeStr: string = date.toLocaleTimeString('en-us', { hour12: false }) + '.' + new Intl.NumberFormat('en-us', { minimumIntegerDigits: 3 }).format(date.getMilliseconds()); + const date: Date = new Date(); + const timeStr: string = + date.toLocaleTimeString('en-us', { hour12: false }) + + '.' + + new Intl.NumberFormat('en-us', { minimumIntegerDigits: 3 }).format(date.getMilliseconds()); - const screenshotPath: string = `${executionScreenCastDir}/${formattedMethodIndex}-${formattedScreenshotIndex}--(${StringUtil.sanitizeTitle(timeStr)})_${StringUtil.sanitizeTitle(methodName)}.png`; + const screenshotPath: string = `${executionScreenCastDir}/${formattedMethodIndex}-${formattedScreenshotIndex}--(${StringUtil.sanitizeTitle( + timeStr + )})_${StringUtil.sanitizeTitle(methodName)}.png`; - try { - await this.catchScreen(screenshotPath); - } catch (err) { - if (!fs.existsSync(executionScreenCastErrorsDir)) { - fs.mkdirSync(executionScreenCastErrorsDir); - } + try { + await this.catchScreen(screenshotPath); + } catch (err) { + if (!fs.existsSync(executionScreenCastErrorsDir)) { + fs.mkdirSync(executionScreenCastErrorsDir); + } - let errorLogFilePath: string = screenshotPath.replace('.png', '.txt'); - errorLogFilePath = errorLogFilePath.replace(executionScreenCastDir, executionScreenCastErrorsDir); - if (err instanceof error.IError) { - await this.writeErrorLog(errorLogFilePath, err); - } - } - } + let errorLogFilePath: string = screenshotPath.replace('.png', '.txt'); + errorLogFilePath = errorLogFilePath.replace(executionScreenCastDir, executionScreenCastErrorsDir); + if (err instanceof error.IError) { + this.writeErrorLog(errorLogFilePath, err); + } + } + } - async catchScreen(screenshotPath: string): Promise { - const screenshot: string = await this.driverHelper.getDriver().takeScreenshot(); - const screenshotStream: WriteStream = fs.createWriteStream(screenshotPath); - screenshotStream.write(Buffer.from(screenshot, 'base64')); - screenshotStream.end(); - } + async catchScreen(screenshotPath: string): Promise { + const screenshot: string = await this.driverHelper.getDriver().takeScreenshot(); + const screenshotStream: WriteStream = fs.createWriteStream(screenshotPath); + screenshotStream.write(Buffer.from(screenshot, 'base64')); + screenshotStream.end(); + } - async writeErrorLog(errorLogPath: string, err: error.IError): Promise { - console.log(`Failed to save screenshot, additional information in the ${errorLogPath}`); - - if (err.stack) { - const screenshotStream: WriteStream = fs.createWriteStream(errorLogPath); - screenshotStream.write(Buffer.from(err.stack, 'utf8')); - screenshotStream.end(); - } - } + writeErrorLog(errorLogPath: string, err: error.IError): void { + console.log(`Failed to save screenshot, additional information in the ${errorLogPath}`); + if (err.stack) { + const screenshotStream: WriteStream = fs.createWriteStream(errorLogPath); + screenshotStream.write(Buffer.from(err.stack, 'utf8')); + screenshotStream.end(); + } + } } diff --git a/tests/e2e/utils/ShellExecutor.ts b/tests/e2e/utils/ShellExecutor.ts index d189ba61311..6da7de07fa2 100644 --- a/tests/e2e/utils/ShellExecutor.ts +++ b/tests/e2e/utils/ShellExecutor.ts @@ -1,17 +1,25 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ import { echo, exec, ShellString } from 'shelljs'; export class ShellExecutor { + static wait(seconds: number): void { + this.execWithLog(`sleep ${seconds}s`); + } - static wait(seconds: number): void { - this.execWithLog(`sleep ${seconds}s`); - } + static curl(link: string): ShellString { + return this.execWithLog(`curl -k ${link}`); + } - static curl(link: string): ShellString { - return this.execWithLog(`curl -k ${link}`); - } - - protected static execWithLog(command: string): ShellString { - echo(command); - return exec(command); - } + protected static execWithLog(command: string): ShellString { + echo(command); + return exec(command); + } } diff --git a/tests/e2e/utils/StringUtil.ts b/tests/e2e/utils/StringUtil.ts index 421068da7c8..9722b554d6d 100644 --- a/tests/e2e/utils/StringUtil.ts +++ b/tests/e2e/utils/StringUtil.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -13,37 +13,45 @@ import { Logger } from './Logger'; @injectable() export class StringUtil { - /** - * 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", "main" or "tree" 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 - */ - static getProjectNameFromGitUrl(url: string): string { - Logger.debug(`${url}`); - if (url.includes('?')) { - url = url.substring(0, url.indexOf('?')); - } - if (url.includes('/tree/')) { - url = url.split('/').slice(0, -2).join('/'); - } - const projectName: string = url.split(/[\/.]/).filter((e: string) => !['git', ''].includes(e)).reverse()[0]; - Logger.debug(`${projectName}`); - return projectName; - } + /** + * 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", "main" or "tree" 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 + */ + static getProjectNameFromGitUrl(url: string): string { + Logger.debug(`${url}`); + if (url.includes('?')) { + url = url.substring(0, url.indexOf('?')); + } + if (url.includes('/tree/')) { + url = url.split('/').slice(0, -2).join('/'); + } + const projectName: string = url + .split(/[\/.]/) + .filter((e: string): boolean => !['git', ''].includes(e)) + .reverse()[0]; + Logger.debug(`${projectName}`); + return projectName; + } - static sanitizeTitle(arg: string): string { - return arg.replace(/\//g, '+').replace(/,/g, '.').replace(/:/g, '-').replace(/['"]/g, '').replace(/[^a-z0-9+\-.()\[\]_]/gi, '_'); - } + static sanitizeTitle(arg: string): string { + return arg + .replace(/\//g, '+') + .replace(/,/g, '.') + .replace(/:/g, '-') + .replace(/['"]/g, '') + .replace(/[^a-z0-9+\-.()\[\]_]/gi, '_'); + } - /** - * Replaces ${ENV}, $ENV to "$ENV" - * @param command string command with environmental variables in unsupported format - * @return updated command with environmental variables in supported format - */ + /** + * replaces ${ENV}, $ENV to "$ENV" + * @param command string command with environmental variables in unsupported format + * @return updated command with environmental variables in supported format + */ - static updateCommandEnvsToShStyle(command: string): string { - return command.replace(/[{}]/g, '').replace(/(? { - try { - let request_censored: AxiosRequestConfig = JSON.parse(JSON.stringify(request)); - if (request_censored === undefined) { - Logger.error('JSON.parse returned an undefined object, cannot process request'); - return request; - } - if (request_censored.headers === undefined) { - Logger.warn('request does not contain any headers object'); - return request; - } - request_censored.headers.Authorization = 'CENSORED'; - request_censored.headers.Cookie = 'CENSORED'; - Logger.info(`request:\n` + request_censored); - } catch (err) { - Logger.error(`request: Failed to deep clone AxiosRequestConfig:` + err); - } - return request; - }); - } + /** + * this method adds a request interceptor into axios request interceptors list and returns an ID of the interceptor + */ + static enableRequestInterceptor(): number { + Logger.debug(); + return axios.interceptors.request.use((request: AxiosRequestConfig): AxiosRequestConfig => { + try { + const REQUEST_CENSORED: AxiosRequestConfig = JSON.parse(JSON.stringify(request)); + if (REQUEST_CENSORED === undefined) { + Logger.error('JSON.parse returned an undefined object, cannot process request'); + return request; + } + if (REQUEST_CENSORED.headers === undefined) { + Logger.warn('request does not contain any headers object'); + return request; + } + REQUEST_CENSORED.headers.Authorization = 'CENSORED'; + REQUEST_CENSORED.headers.Cookie = 'CENSORED'; + Logger.info('request:\n' + JSON.stringify(REQUEST_CENSORED)); + } catch (err) { + Logger.error('request: Failed to deep clone AxiosRequestConfig:' + err); + } + return request; + }); + } - /** - * This method adds a response interceptor into axios response interceptors list and returns an ID of the interceptor - */ - static enableResponseInterceptor(): number { - Logger.debug(); - return axios.interceptors.response.use(response => { - try { - let response_censored: AxiosResponse = JSON.parse(JSON.stringify(response, (key, value) => { - switch (key) { - case 'request': - return 'CENSORED'; - default: - return value; - } - })); - if (response_censored === undefined) { - Logger.error('JSON.parse returned an undefined object, cannot process response'); - return response; - } - if (response_censored.config === undefined) { - Logger.warn('response does not contain any config object'); - return response; - } - if (response_censored.config.headers === undefined) { - Logger.warn('response does not contain any config.headers object'); - return response; - } - response_censored.config.headers.Authorization = 'CENSORED'; - response_censored.config.headers.Cookie = 'CENSORED'; - if (response_censored.data.access_token !== null) { - response_censored.data.access_token = 'CENSORED'; - } - if (response_censored.data.refresh_token !== null) { - response_censored.data.refresh_token = 'CENSORED'; - } - Logger.info(`response:\n` + response_censored); - } catch (err) { - Logger.error(`response: Failed to deep clone AxiosResponse:` + err); - } - return response; - }); - } + /** + * this method adds a response interceptor into axios response interceptors list and returns an ID of the interceptor + */ + static enableResponseInterceptor(): number { + Logger.debug(); + return axios.interceptors.response.use((response: AxiosResponse): AxiosResponse => { + try { + const RESPONSE_CENSORED: AxiosResponse = JSON.parse( + JSON.stringify(response, (key, value: string): string => { + switch (key) { + case 'request': + return 'CENSORED'; + default: + return value; + } + }) + ); + if (RESPONSE_CENSORED === undefined) { + Logger.error('JSON.parse returned an undefined object, cannot process response'); + return response; + } + if (RESPONSE_CENSORED.config === undefined) { + Logger.warn('response does not contain any config object'); + return response; + } + if (RESPONSE_CENSORED.config.headers === undefined) { + Logger.warn('response does not contain any config.headers object'); + return response; + } + RESPONSE_CENSORED.config.headers.Authorization = 'CENSORED'; + RESPONSE_CENSORED.config.headers.Cookie = 'CENSORED'; + if (RESPONSE_CENSORED.data.access_token !== null) { + RESPONSE_CENSORED.data.access_token = 'CENSORED'; + } + if (RESPONSE_CENSORED.data.refresh_token !== null) { + RESPONSE_CENSORED.data.refresh_token = 'CENSORED'; + } + Logger.info('response:\n' + JSON.stringify(RESPONSE_CENSORED)); + } catch (err) { + Logger.error('response: Failed to deep clone AxiosResponse:' + err); + } + return response; + }); + } - constructor(@inject(TYPES.IAuthorizationHeaderHandler) private readonly headerHandler: IAuthorizationHeaderHandler) { } + async get(relativeUrl: string): Promise { + return await axios.get(this.assembleUrl(relativeUrl), await this.headerHandler.get()); + } - async get(relativeUrl: string): Promise { - return await axios.get(this.assembleUrl(relativeUrl), await this.headerHandler.get()); - } + async post(relativeUrl: string, data?: string): Promise { + return await axios.post(this.assembleUrl(relativeUrl), data, await this.headerHandler.get()); + } - async post(relativeUrl: string, data?: string | any): Promise { - return await axios.post(this.assembleUrl(relativeUrl), data, await this.headerHandler.get()); - } + async delete(relativeUrl: string): Promise { + return await axios.delete(this.assembleUrl(relativeUrl), await this.headerHandler.get()); + } - async delete(relativeUrl: string): Promise { - return await axios.delete(this.assembleUrl(relativeUrl), await this.headerHandler.get()); - } - - async patch(relativeUrl: string, patchParams: object): Promise { - return await axios.patch(this.assembleUrl(relativeUrl), patchParams, await this.headerHandler.get()); - } - - private assembleUrl(relativeUrl: string): string { - return `${BaseTestConstants.TS_SELENIUM_BASE_URL}/${relativeUrl}`; - } + async patch(relativeUrl: string, patchParams: object): Promise { + return await axios.patch(this.assembleUrl(relativeUrl), patchParams, await this.headerHandler.get()); + } + private assembleUrl(relativeUrl: string): string { + return `${BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL}/${relativeUrl}`; + } } diff --git a/tests/e2e/utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler.ts b/tests/e2e/utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler.ts index 6c23b066684..632f2625c16 100644 --- a/tests/e2e/utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler.ts +++ b/tests/e2e/utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -14,29 +14,40 @@ import { DriverHelper } from '../../DriverHelper'; import { CLASSES } from '../../../configs/inversify.types'; import { Logger } from '../../Logger'; import { IWebDriverCookie } from 'selenium-webdriver'; -import { BaseTestConstants, Platform } from '../../../constants/BaseTestConstants'; +import { BASE_TEST_CONSTANTS, Platform } from '../../../constants/BASE_TEST_CONSTANTS'; @injectable() export class CheMultiuserAuthorizationHeaderHandler implements IAuthorizationHeaderHandler { - private authorizationToken: string = ''; - private readonly cookiesType: string = BaseTestConstants.TS_PLATFORM === Platform.OPENSHIFT ? '_oauth_proxy' : '_oauth2_proxy'; + private authorizationToken: string = ''; + private readonly cookiesType: string = BASE_TEST_CONSTANTS.TS_PLATFORM === Platform.OPENSHIFT ? '_oauth_proxy' : '_oauth2_proxy'; - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - async get(): Promise { - try { - let token: IWebDriverCookie = await this.driverHelper.getDriver().manage().getCookie(this.cookiesType); - if (this.authorizationToken !== token.value) { - this.authorizationToken = token.value; - } - } catch (err) { - if (this.authorizationToken.length > 0) { - Logger.warn(`could not obtain _oauth_proxy cookie from chromedriver, browser session may have been killed. Using stored value.`); - } else { - throw new Error(`Could not obtain _oauth_proxy cookie from chromedriver, browser session may have been killed. No stored token present!`); - } - } + async get(): Promise { + try { + const token: IWebDriverCookie = await this.driverHelper.getDriver().manage().getCookie(this.cookiesType); + if (this.authorizationToken !== token.value) { + this.authorizationToken = token.value; + } + } catch (err) { + if (this.authorizationToken.length > 0) { + Logger.warn( + 'could not obtain _oauth_proxy cookie from chromedriver, browser session may have been killed. Using stored value.' + ); + } else { + throw new Error( + 'Could not obtain _oauth_proxy cookie from chromedriver, browser session may have been killed. No stored token present!' + ); + } + } - return { headers: { 'cookie': `${this.cookiesType}=${this.authorizationToken}` } }; - } + return { + headers: { + cookie: `${this.cookiesType}=${this.authorizationToken}` + } + }; + } } diff --git a/tests/e2e/utils/request-handlers/headers/IAuthorizationHeaderHandler.ts b/tests/e2e/utils/request-handlers/headers/IAuthorizationHeaderHandler.ts index 4172e323b63..8bcd9d0d929 100644 --- a/tests/e2e/utils/request-handlers/headers/IAuthorizationHeaderHandler.ts +++ b/tests/e2e/utils/request-handlers/headers/IAuthorizationHeaderHandler.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -11,5 +11,5 @@ import { AxiosRequestConfig } from 'axios'; export interface IAuthorizationHeaderHandler { - get(): Promise; + get(): Promise; } diff --git a/tests/e2e/utils/workspace/ApiUrlResolver.ts b/tests/e2e/utils/workspace/ApiUrlResolver.ts index b7d42bda392..6a8fe31b2fd 100644 --- a/tests/e2e/utils/workspace/ApiUrlResolver.ts +++ b/tests/e2e/utils/workspace/ApiUrlResolver.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -15,33 +15,38 @@ import { AxiosResponse } from 'axios'; @injectable() export class ApiUrlResolver { - private static readonly DASHBOARD_API_URL: string = 'dashboard/api/namespace'; - private static readonly KUBERNETES_API_URL: string = 'api/kubernetes/namespace'; + private static readonly DASHBOARD_API_URL: string = 'dashboard/api/namespace'; + private static readonly KUBERNETES_API_URL: string = 'api/kubernetes/namespace'; - private userNamespace: string = ''; + private userNamespace: string = ''; - constructor(@inject(CLASSES.CheApiRequestHandler) private readonly processRequestHandler: CheApiRequestHandler) {} + constructor( + @inject(CLASSES.CheApiRequestHandler) + private readonly processRequestHandler: CheApiRequestHandler + ) {} - async getWorkspaceApiUrl(workspaceName: string): Promise { - return `${await this.getWorkspacesApiUrl()}/${workspaceName}`; - } + async getWorkspaceApiUrl(workspaceName: string): Promise { + return `${await this.getWorkspacesApiUrl()}/${workspaceName}`; + } - async getWorkspacesApiUrl(): Promise { - const namespace: string = await this.obtainUserNamespace(); - return `${ApiUrlResolver.DASHBOARD_API_URL}/${namespace}/devworkspaces`; - } + async getWorkspacesApiUrl(): Promise { + const namespace: string = await this.obtainUserNamespace(); + return `${ApiUrlResolver.DASHBOARD_API_URL}/${namespace}/devworkspaces`; + } - private async obtainUserNamespace(): Promise { - Logger.debug(`${this.userNamespace}`); - if (this.userNamespace.length === 0) { - Logger.trace(`USER_NAMESPACE.length = 0, calling kubernetes API`); - const kubernetesResponse: AxiosResponse = await this.processRequestHandler.get(ApiUrlResolver.KUBERNETES_API_URL); - if (kubernetesResponse.status !== 200) { - throw new Error(`Cannot get user namespace from kubernetes API. Code: ${kubernetesResponse.status} Data: ${kubernetesResponse.data}`); - } - this.userNamespace = kubernetesResponse.data[0].name; - Logger.debug(`kubeapi success: ${this.userNamespace}`); - } - return this.userNamespace; - } + private async obtainUserNamespace(): Promise { + Logger.debug(`${this.userNamespace}`); + if (this.userNamespace.length === 0) { + Logger.trace('USER_NAMESPACE.length = 0, calling kubernetes API'); + const kubernetesResponse: AxiosResponse = await this.processRequestHandler.get(ApiUrlResolver.KUBERNETES_API_URL); + if (kubernetesResponse.status !== 200) { + throw new Error( + `Cannot get user namespace from kubernetes API. Code: ${kubernetesResponse.status} Data: ${kubernetesResponse.data}` + ); + } + this.userNamespace = kubernetesResponse.data[0].name; + Logger.debug(`kubeapi success: ${this.userNamespace}`); + } + return this.userNamespace; + } } diff --git a/tests/e2e/utils/workspace/ITestWorkspaceUtil.ts b/tests/e2e/utils/workspace/ITestWorkspaceUtil.ts index 1426fda1af1..676bc71f823 100644 --- a/tests/e2e/utils/workspace/ITestWorkspaceUtil.ts +++ b/tests/e2e/utils/workspace/ITestWorkspaceUtil.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -11,33 +11,33 @@ import { WorkspaceStatus } from './WorkspaceStatus'; export interface ITestWorkspaceUtil { - waitWorkspaceStatus(namespace: string, workspaceName: string, expectedWorkspaceStatus: WorkspaceStatus): void; - - stopWorkspaceByName(workspaceName: string): void; - - /** - * Delete a workspace without stopping phase (similar with force deleting) - */ - deleteWorkspaceByName(workspaceName: string): void; - - /** - * Stop workspace before deleting with checking stopping phase - */ - stopAndDeleteWorkspaceByName(workspaceName: string): void; - - /** - * Stop all run workspaces in the namespace - */ - stopAllRunningWorkspaces(namespace: string): void; - - /** - * Stop all run workspaces, check statused and remove the workspaces - */ - stopAndDeleteAllRunningWorkspaces(namespace: string): void; - - /** - * Stop all run workspaces without stopping and waiting for of 'Stopped' phase - * Similar with 'force' deleting - */ - deleteAllWorkspaces(namespace: string): void; + waitWorkspaceStatus(namespace: string, workspaceName: string, expectedWorkspaceStatus: WorkspaceStatus): void; + + stopWorkspaceByName(workspaceName: string): void; + + /** + * delete a workspace without stopping phase (similar with force deleting) + */ + deleteWorkspaceByName(workspaceName: string): void; + + /** + * stop workspace before deleting with checking stopping phase + */ + stopAndDeleteWorkspaceByName(workspaceName: string): void; + + /** + * stop all run workspaces in the namespace + */ + stopAllRunningWorkspaces(namespace: string): void; + + /** + * stop all run workspaces, check statused and remove the workspaces + */ + stopAndDeleteAllRunningWorkspaces(namespace: string): void; + + /** + * stop all run workspaces without stopping and waiting for of 'Stopped' phase + * Similar with 'force' deleting + */ + deleteAllWorkspaces(namespace: string): void; } diff --git a/tests/e2e/utils/workspace/TestWorkspaceUtil.ts b/tests/e2e/utils/workspace/TestWorkspaceUtil.ts index 2df5c0b5152..681ca6fc260 100644 --- a/tests/e2e/utils/workspace/TestWorkspaceUtil.ts +++ b/tests/e2e/utils/workspace/TestWorkspaceUtil.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -19,150 +19,157 @@ import { Logger } from '../Logger'; import axios, { AxiosResponse } from 'axios'; import { ITestWorkspaceUtil } from './ITestWorkspaceUtil'; import { ApiUrlResolver } from './ApiUrlResolver'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; @injectable() export class TestWorkspaceUtil implements ITestWorkspaceUtil { - readonly polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING; - readonly attempts: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT / this.polling; - - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, - @inject(CLASSES.CheApiRequestHandler) private readonly processRequestHandler: CheApiRequestHandler, - @inject(CLASSES.ApiUrlResolver) private readonly apiUrlResolver: ApiUrlResolver - ) { } - - async waitWorkspaceStatus(workspaceName: string, expectedWorkspaceStatus: WorkspaceStatus): Promise { - Logger.debug(); - - let workspaceStatus: string = ''; - let expectedStatus: boolean = false; - for (let i: number = 0; i < this.attempts; i++) { - const response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName)); - - if (response.status !== 200) { - throw new Error(`Can not get status of a workspace. Code: ${response.status} Data: ${response.data}`); - } - - workspaceStatus = await response.data.status.phase; - - if (workspaceStatus === expectedWorkspaceStatus) { - expectedStatus = true; - break; - } - - await this.driverHelper.wait(this.polling); - } - - if (!expectedStatus) { - let waitTime: number = this.attempts * this.polling; - throw new error.TimeoutError(`The workspace was not stopped in ${waitTime} ms. Current status is: ${workspaceStatus}`); - } - } - - async stopWorkspaceByName(workspaceName: string): Promise { - Logger.debug(`${workspaceName}`); - - const stopWorkspaceApiUrl: string = await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName); - let stopWorkspaceResponse: AxiosResponse; - - try { - stopWorkspaceResponse = await this.processRequestHandler.patch(stopWorkspaceApiUrl, [{ - 'op': 'replace', - 'path': '/spec/started', - 'value': false - }]); - } catch (err) { - Logger.error(`stop workspace call failed. URL used: ${stopWorkspaceApiUrl}`); - throw err; - } - - if (stopWorkspaceResponse.status !== 200) { - throw new Error(`Cannot stop workspace. Code: ${stopWorkspaceResponse.status} Data: ${stopWorkspaceResponse.data}`); - } - - await this.waitWorkspaceStatus(workspaceName, WorkspaceStatus.STOPPED); - Logger.debug(`${workspaceName} stopped successfully`); - } - - // delete a workspace without stopping phase (similar with force deleting) - async deleteWorkspaceByName(workspaceName: string): Promise { - Logger.debug(`${workspaceName}`); - - const deleteWorkspaceApiUrl: string = await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName); - let deleteWorkspaceResponse: AxiosResponse; - let deleteWorkspaceStatus: boolean = false; - try { - deleteWorkspaceResponse = await this.processRequestHandler.delete(deleteWorkspaceApiUrl); - } catch (error) { - if (axios.isAxiosError(error) && error.response?.status === 404) { - Logger.error(`the workspace :${workspaceName} not found`); - throw error; - } - Logger.error(`delete workspace call failed. URL used: ${deleteWorkspaceStatus}`); - throw error; - } - - if (deleteWorkspaceResponse.status !== 204) { - throw new Error(`Can not delete workspace. Code: ${deleteWorkspaceResponse.status} Data: ${deleteWorkspaceResponse.data}`); - } - - for (let i: number = 0; i < this.attempts; i++) { - try { - deleteWorkspaceResponse = await this.processRequestHandler.get(deleteWorkspaceApiUrl); - } catch (error) { - if (axios.isAxiosError(error) && error.response?.status === 404) { - deleteWorkspaceStatus = true; - Logger.debug(`${workspaceName} deleted successfully`); - break; - } - } - } - - if (!deleteWorkspaceStatus) { - let waitTime: number = this.attempts * this.polling; - throw new error.TimeoutError(`The workspace was not deleted in ${waitTime} ms.`); - } - } - - // stop workspace before deleting with checking stopping phase - async stopAndDeleteWorkspaceByName(workspaceName: string): Promise { - Logger.debug(); - - await this.stopWorkspaceByName(workspaceName); - await this.deleteWorkspaceByName(workspaceName); - } - - // stop all run workspaces in the namespace - async stopAllRunningWorkspaces(namespace: string): Promise { - Logger.debug(); - let response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl()); - for (let i: number = 0; i < response.data.items.length; i++) { - Logger.info('the project is being stopped: ' + response.data.items[i].metadata.name); - await this.stopWorkspaceByName(response.data.items[i].metadata.name); - } - } - - // stop all run workspaces, check statuses and remove the workspaces - async stopAndDeleteAllRunningWorkspaces(namespace: string): Promise { - Logger.debug(); - let response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl()); - await this.stopAllRunningWorkspaces(namespace); - for (let i: number = 0; i < response.data.items.length; i++) { - Logger.info('the project is being deleted: ' + response.data.items[i].metadata.name); - await this.deleteWorkspaceByName(response.data.items[i].metadata.name); - } - } - - // stop all run workspaces without stopping and waiting for of 'Stopped' phase - // similar with 'force' deleting - async deleteAllWorkspaces(namespace: string): Promise { - Logger.debug(); - let response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl()); - - for (let i: number = 0; i < response.data.items.length; i++) { - Logger.info('the project is being deleted .......: ' + response.data.items[i].metadata.name); - await this.deleteWorkspaceByName(response.data.items[i].metadata.name); - } - } + readonly polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + readonly attempts: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT / this.polling; + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper, + @inject(CLASSES.CheApiRequestHandler) + private readonly processRequestHandler: CheApiRequestHandler, + @inject(CLASSES.ApiUrlResolver) + private readonly apiUrlResolver: ApiUrlResolver + ) {} + + async waitWorkspaceStatus(workspaceName: string, expectedWorkspaceStatus: WorkspaceStatus): Promise { + Logger.debug(); + + let workspaceStatus: string = ''; + let expectedStatus: boolean = false; + for (let i: number = 0; i < this.attempts; i++) { + const response: AxiosResponse = await this.processRequestHandler.get( + await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName) + ); + + if (response.status !== 200) { + throw new Error(`Can not get status of a workspace. Code: ${response.status} Data: ${response.data}`); + } + + workspaceStatus = await response.data.status.phase; + + if (workspaceStatus === expectedWorkspaceStatus) { + expectedStatus = true; + break; + } + + await this.driverHelper.wait(this.polling); + } + + if (!expectedStatus) { + const waitTime: number = this.attempts * this.polling; + throw new error.TimeoutError(`The workspace was not stopped in ${waitTime} ms. Current status is: ${workspaceStatus}`); + } + } + + async stopWorkspaceByName(workspaceName: string): Promise { + Logger.debug(`${workspaceName}`); + + const stopWorkspaceApiUrl: string = await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName); + let stopWorkspaceResponse: AxiosResponse; + + try { + stopWorkspaceResponse = await this.processRequestHandler.patch(stopWorkspaceApiUrl, [ + { + op: 'replace', + path: '/spec/started', + value: false + } + ]); + } catch (err) { + Logger.error(`stop workspace call failed. URL used: ${stopWorkspaceApiUrl}`); + throw err; + } + + if (stopWorkspaceResponse.status !== 200) { + throw new Error(`Cannot stop workspace. Code: ${stopWorkspaceResponse.status} Data: ${stopWorkspaceResponse.data}`); + } + + await this.waitWorkspaceStatus(workspaceName, WorkspaceStatus.STOPPED); + Logger.debug(`${workspaceName} stopped successfully`); + } + + // delete a workspace without stopping phase (similar with force deleting) + async deleteWorkspaceByName(workspaceName: string): Promise { + Logger.debug(`${workspaceName}`); + + const deleteWorkspaceApiUrl: string = await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName); + let deleteWorkspaceResponse: AxiosResponse; + let deleteWorkspaceStatus: boolean = false; + try { + deleteWorkspaceResponse = await this.processRequestHandler.delete(deleteWorkspaceApiUrl); + } catch (error) { + if (axios.isAxiosError(error) && error.response?.status === 404) { + Logger.error(`the workspace :${workspaceName} not found`); + throw error; + } + Logger.error(`delete workspace call failed. URL used: ${deleteWorkspaceStatus}`); + throw error; + } + + if (deleteWorkspaceResponse.status !== 204) { + throw new Error(`Can not delete workspace. Code: ${deleteWorkspaceResponse.status} Data: ${deleteWorkspaceResponse.data}`); + } + + for (let i: number = 0; i < this.attempts; i++) { + try { + deleteWorkspaceResponse = await this.processRequestHandler.get(deleteWorkspaceApiUrl); + } catch (error) { + if (axios.isAxiosError(error) && error.response?.status === 404) { + deleteWorkspaceStatus = true; + Logger.debug(`${workspaceName} deleted successfully`); + break; + } + } + } + + if (!deleteWorkspaceStatus) { + const waitTime: number = this.attempts * this.polling; + throw new error.TimeoutError(`The workspace was not deleted in ${waitTime} ms.`); + } + } + + // stop workspace before deleting with checking stopping phase + async stopAndDeleteWorkspaceByName(workspaceName: string): Promise { + Logger.debug(); + + await this.stopWorkspaceByName(workspaceName); + await this.deleteWorkspaceByName(workspaceName); + } + + // stop all run workspaces in the namespace + async stopAllRunningWorkspaces(): Promise { + Logger.debug(); + const response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl()); + for (let i: number = 0; i < response.data.items.length; i++) { + Logger.info('the project is being stopped: ' + response.data.items[i].metadata.name); + await this.stopWorkspaceByName(response.data.items[i].metadata.name); + } + } + + // stop all run workspaces, check statuses and remove the workspaces + async stopAndDeleteAllRunningWorkspaces(): Promise { + Logger.debug(); + const response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl()); + await this.stopAllRunningWorkspaces(); + for (let i: number = 0; i < response.data.items.length; i++) { + Logger.info('the project is being deleted: ' + response.data.items[i].metadata.name); + await this.deleteWorkspaceByName(response.data.items[i].metadata.name); + } + } + + // stop all run workspaces without stopping and waiting for of 'Stopped' phase + // similar with 'force' deleting + async deleteAllWorkspaces(): Promise { + Logger.debug(); + const response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl()); + + for (let i: number = 0; i < response.data.items.length; i++) { + Logger.info('the project is being deleted .......: ' + response.data.items[i].metadata.name); + await this.deleteWorkspaceByName(response.data.items[i].metadata.name); + } + } } diff --git a/tests/e2e/utils/workspace/WorkspaceStatus.ts b/tests/e2e/utils/workspace/WorkspaceStatus.ts index 953b5fd0b2b..57afdad23b9 100644 --- a/tests/e2e/utils/workspace/WorkspaceStatus.ts +++ b/tests/e2e/utils/workspace/WorkspaceStatus.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2019-2023 Red Hat, Inc. +/** ******************************************************************* + * 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 @@ -9,7 +9,7 @@ **********************************************************************/ export enum WorkspaceStatus { - RUNNING = 'Running', - STOPPED = 'Stopped', - STARTING = 'Starting' + RUNNING = 'Running', + STOPPED = 'Stopped', + STARTING = 'Starting' }