diff --git a/.che/che-editor.yaml b/.che/che-editor.yaml new file mode 100644 index 00000000000..b096f7f98bf --- /dev/null +++ b/.che/che-editor.yaml @@ -0,0 +1 @@ +id: che-incubator/che-code/insiders diff --git a/.devfile.yaml b/.devfile.yaml index b20476e9a4c..9bd883b028f 100644 --- a/.devfile.yaml +++ b/.devfile.yaml @@ -6,19 +6,34 @@ # # SPDX-License-Identifier: EPL-2.0 # -schemaVersion: 2.1.0 +schemaVersion: 2.2.2 metadata: name: che + language: typescript attributes: - controller.devfile.io/storage-type: ephemeral + controller.devfile.io/scc: container-build + controller.devfile.io/storage-type: per-workspace +projects: + - name: che + git: + remotes: + origin: 'https://github.com/eclipse/che.git' + checkoutFrom: + remote: origin + revision: main components: - name: devtools container: - image: quay.io/mloriedo/universal-developer-image:ubi8-latest - memoryLimit: 4G + image: quay.io/devfile/universal-developer-image:ubi8-latest + memoryLimit: 12G memoryRequest: 256Mi - cpuLimit: 500m + cpuLimit: '2' cpuRequest: 30m + mountSources: true + sourceMapping: /projects + env: + - name: KUBEDOCK_ENABLED + value: 'true' commands: - id: update-contributing exec: @@ -28,3 +43,38 @@ commands: exec: commandLine: '.repositories-update-contributing.sh IN_DOCKER' component: devtools +- id: tests-update-dependencies + exec: + commandLine: >- + cd tests/e2e && + echo "Installing/Updating nvm" && + curl -so- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash && + export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && + nvm --version && + echo "Updating nodejs" && + nvm install lts/hydrogen && nvm alias default lts/hydrogen && nvm use default && + echo "Updating npm" && + npm install -g npm && + echo "Installing test dependencies" && + rm -rf package-lock.json && + npm install && + npm uninstall chromedriver && npm install chromedriver --save-dev && + cd ../../ + component: devtools +- id: tests-lint-project + exec: + commandLine: >- + cd tests/e2e && + npm run lint + component: devtools +- id: tests-build-tests + exec: + commandLine: >- + cd tests/e2e && + npm run tsc + component: devtools +- id: tests-happy-path-remote + exec: + commandLine: >- + echo "TODO: Start pod in dogfooding user namespace and collect logs" + component: devtools diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0438a3140b3..fcbb0de18d0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,11 +1,8 @@ # Global Owners -* @nickboldt - -# dockerfiles -dockerfiles/** @nickboldt +* @dmytro-ndp @SDawley # e2e tests -tests/e2e/** @musienko-maxim @nickboldt @ScrewTSW @dmytro-ndp +tests/e2e/** @musienko-maxim @dmytro-ndp # devworkspace happy path test tests/devworkspace-happy-path/** @musienko-maxim diff --git a/.github/ISSUE_TEMPLATE/a_question.yaml b/.github/ISSUE_TEMPLATE/a_question.yaml index f29c675853f..37c5fcd9218 100644 --- a/.github/ISSUE_TEMPLATE/a_question.yaml +++ b/.github/ISSUE_TEMPLATE/a_question.yaml @@ -13,11 +13,11 @@ body: Useful Links: - - 📄 Documentation: https://www.eclipse.org/che/docs + - 📄 Documentation: https://eclipse.dev/che/docs - 📝 Contributing: https://github.com/eclipse/che/blob/master/CONTRIBUTING.md 💬 Eclipse Che has public chat on: - - Mattermost: https://mattermost.eclipse.org/eclipse/channels/eclipse-che + - Eclipse Cloud Dev Tools Slack: https://communityinviter.com/apps/ecd-tools/join-the-community - type: textarea id: summary diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 3ef6684a332..ebfb6d4905e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -13,11 +13,11 @@ body: Useful Links: - - 📄 Documentation: https://www.eclipse.org/che/docs + - 📄 Documentation: https://eclipse.dev/che/docs - 📝 Contributing: https://github.com/eclipse/che/blob/master/CONTRIBUTING.md 💬 Eclipse Che has public chat on: - - Mattermost: https://mattermost.eclipse.org/eclipse/channels/eclipse-che + - Eclipse Cloud Dev Tools Slack: https://communityinviter.com/apps/ecd-tools/join-the-community - type: textarea id: describe-bug @@ -33,8 +33,26 @@ body: label: Che version description: if workspace is running, version can be obtained with help/about menu options: - - "7.71@latest" + - "7.90@latest" - "next (development version)" + - "7.89" + - "7.88" + - "7.87" + - "7.86" + - "7.85" + - "7.84" + - "7.83" + - "7.82" + - "7.81" + - "7.80" + - "7.79" + - "7.78" + - "7.77" + - "7.75" + - "7.74" + - "7.73" + - "7.72" + - "7.71" - "7.70" - "7.69" - "7.68" @@ -150,7 +168,7 @@ body: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks - description: "How to collect logs: https://www.eclipse.org/che/docs/che-7/collecting-logs-using-chectl" + description: "How to collect logs: https://eclipse.dev/che/docs/stable/administration-guide/collecting-logs-using-chectl/" render: shell - type: textarea diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml.orig b/.github/ISSUE_TEMPLATE/bug_report.yml.orig new file mode 100644 index 00000000000..d54fe80ff6b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml.orig @@ -0,0 +1,184 @@ +name: Bug report 🐞 +description: Report a bug found in Eclipse Che +labels: [kind/bug] + +body: + - type: markdown + attributes: + value: | + ### Creating a new Bug 🐞 + 🔍 Before opening a new issue please search existing issues at https://github.com/eclipse/che/issues + + 🤔 To make it easier for us to help you, please include as much useful information as possible. + + Useful Links: + + - 📄 Documentation: https://eclipse.dev/che/docs + - 📝 Contributing: https://github.com/eclipse/che/blob/master/CONTRIBUTING.md + + 💬 Eclipse Che has public chat on: + - Eclipse Cloud Dev Tools Slack: https://communityinviter.com/apps/ecd-tools/join-the-community + + - type: textarea + id: describe-bug + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. + placeholder: Describe the bug + validations: + required: true + - type: dropdown + id: version + attributes: + label: Che version + description: if workspace is running, version can be obtained with help/about menu + options: +<<<<<<< HEAD + - "7.71@latest" + - "next (development version)" +======= + - "7.90@latest" + - "next (development version)" + - "7.89" + - "7.88" + - "7.87" + - "7.86" + - "7.85" + - "7.84" + - "7.83" + - "7.82" + - "7.81" + - "7.80" + - "7.79" + - "7.78" + - "7.77" + - "7.75" + - "7.74" + - "7.73" + - "7.72" + - "7.71" +>>>>>>> main + - "7.70" + - "7.69" + - "7.68" + - "7.67" + - "7.66" + - "7.65" + - "7.64" + - "7.63" + - "7.61" + - "7.60" + - "7.59" + - "7.58" + - "7.57" + - "7.56" + - "7.55" + - "7.54" + - "7.53" + - "7.52" + - "7.51" + - "7.50" + - "7.49" + - "7.48" + - "7.47" + - "7.46" + - "7.45" + - "7.44" + - "7.43" + - "7.42" + - "7.41" + - "7.40" + - "7.39" + - "other (please specify in additional context)" + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: What are the steps to reproduce this bug ? + placeholder: | + 1. Do '...' + 2. Click on '....' + 3. See error + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: A clear and concise description of what you expected to happen. + placeholder: + validations: + required: true + + - type: dropdown + id: runtime + attributes: + label: Runtime + description: What is the kubernetes flavor ? + multiple: true + options: + - Kubernetes (vanilla) + - OpenShift + - minikube + - CodeReady Container + - Docker Desktop + - other (please specify in additional context) + validations: + required: true + + - type: textarea + id: screenshots + attributes: + label: Screenshots + description: If applicable, add screenshots to help explain your problem. + + - type: dropdown + id: install-method + attributes: + label: Installation method + multiple: true + options: + - chectl/latest + - chectl/next + - OperatorHub + - other (please specify in additional context) + validations: + required: true + + - type: dropdown + id: environment + attributes: + label: Environment + multiple: true + options: + - Windows + - Linux + - macOS + - Amazon + - Azure + - GCE + - "Dev Sandbox (workspaces.openshift.com)" + - other (please specify in additional context) + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Eclipse Che Logs + placeholder: | + Please copy and paste any relevant log output. + + This will be automatically formatted into code, so no need for backticks + description: "How to collect logs: https://eclipse.dev/che/docs/stable/administration-guide/collecting-logs-using-chectl/" + render: shell + + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Add any other context about the problem here. + placeholder: diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 77cbba9af5a..63f387b4ca4 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -13,11 +13,11 @@ body: Useful Links: - - 📄 Documentation: https://www.eclipse.org/che/docs + - 📄 Documentation: https://eclipse.dev/che/docs - 📝 Contributing: https://github.com/eclipse/che/blob/master/CONTRIBUTING.md 💬 Eclipse Che has public chat on: - - Mattermost: https://mattermost.eclipse.org/eclipse/channels/eclipse-che + - Eclipse Cloud Dev Tools Slack: https://communityinviter.com/apps/ecd-tools/join-the-community - type: textarea id: problem diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index 6cb1a8df85b..a43a3852b4a 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -14,12 +14,10 @@ assignees: '' The following will be released via [che-release](https://github.com/eclipse/che-release/blob/master/cico_release.sh) according to a series of phases: -1. [ ] che-machine-exec, che-server, che-e2e, che-devfile-registry, che-dashboard, jwtproxy, kubernetes image puller -2. [ ] che-theia -3. [ ] che-plugin-registry (once che-theia and machine-exec are done) -4. [ ] che-operator - -Each phase will [send a Mattermost notification to the Eclipse Che releases channel](https://mattermost.eclipse.org/eclipse/channels/eclipse-che-releases). +Phase 1. [ ] che-code, configbump, che-machine-exec, che-server, devworkspace-generator, kubernetes-image-puller. +Phase 2. [ ] che-e2e, che-plugin-registry, che-dashboard . +Phase 3. [ ] che-devfile-registry. +Phase 4. [ ] che-operator. Then, these steps will be done, once the above projects are released and PRs are merged: @@ -27,25 +25,9 @@ Then, these steps will be done, once the above projects are released and PRs are - [ ] [Che community operator PRs for K8S](https://github.com/k8s-operatorhub/community-operators/pulls/che-bot) and [Che community operator PRs for OS](https://github.com/redhat-openshift-ecosystem/community-operators-prod/pulls/che-bot) _(depends on che-operator)_ - [ ] [che-docs PR](https://github.com/eclipse/che-docs/pulls/che-bot) _(depends on che-operator)_ -If this is a .0 release: - -- [ ] complete current milestone - - [ ] move incomplete *deferred* issues to backlog - - [ ] move incomplete *WIP* issues to next milestone - - [ ] close completed issues - - [ ] close milestone - -| Process [1] | Script | Action | Container(s) + Artifact(s) | -| --- | --- | --- | --- | -| [che-release](https://github.com/eclipse/che-release/blob/master/RELEASE.md) | [cico_release.sh](https://github.com/eclipse/che-release/blob/master/cico_release.sh) | [Action](https://github.com/eclipse/che-release/actions?query=workflow%3A%22Release+-+Orchestrate+Overall+Release+Phases%22) | n/a | -| [che-theia](https://github.com/eclipse/che-theia/blob/main/RELEASE.md) | [make-release.sh](https://github.com/eclipse/che-theia/blob/main/make-release.sh) | [Action](https://github.com/eclipse/che-theia/actions?query=workflow%3A%22Release+Che+Theia%22) | [`eclipse/che-theia`](https://quay.io/eclipse/che-theia) | -| [che-machine-exec](https://github.com/eclipse-che/che-machine-exec/blob/master/RELEASE.md) | [make-release.sh](https://github.com/eclipse-che/che-machine-exec/blob/master/make-release.sh) | [Action](https://github.com/eclipse-che/che-machine-exec/actions?query=workflow%3A%22Release+Che+Machine+Exec%22) | [`eclipse/che-machine-exec`](https://quay.io/eclipse/che-machine-exec)| -| [che-devfile-registry](https://github.com/eclipse/che-devfile-registry/blob/master/RELEASE.md) | [make-release.sh](https://github.com/eclipse/che-devfile-registry/blob/master/make-release.sh) | [Action](https://github.com/eclipse/che-devfile-registry/actions?query=workflow%3A%22Release+Che+Devfile+Registry%22) | [`eclipse/che-devfile-registry`](https://quay.io/eclipse/che-devfile-registry)| -| [che-plugin-registry](https://github.com/eclipse/che-plugin-registry/blob/master/RELEASE.md) | [make-release.sh](https://github.com/eclipse/che-plugin-registry/blob/master/make-release.sh) | [Action](https://github.com/eclipse/che-plugin-registry/actions?query=workflow%3A%22Release+Che+Plugin+Registry%22) | [`eclipse/che-plugin-registry`](https://quay.io/eclipse/che-plugin-registry)| -| [che-parent](https://github.com/eclipse/che-parent/blob/master/RELEASE.md) | [make-release.sh](https://github.com/eclipse/che-parent/blob/master/make-release.sh) | [Action](https://github.com/eclipse/che/actions?query=workflow%3A%22Release+Che+Server%22) | [che-server](https://search.maven.org/search?q=a:che-server) [2] | -| [che-dashboard](https://github.com/eclipse-che/che-dashboard/blob/main/RELEASE.md) | [make-release.sh](https://github.com/eclipse-che/che-dashboard/blob/master/make-release.sh) | [Action](https://github.com/eclipse-che/che-dashboard/actions?query=workflow%3A%22Release+Che+Dashboard%22) | [`che-dashboard`](https://quay.io/repository/eclipse/che-dashboard?tag=next&tab=tags) | -| [che](https://github.com/eclipse-che/che-server/blob/HEAD/RELEASE.md) | [make-release.sh](https://github.com/eclipse-che/che-server/blob/HEAD/make-release.sh) | [Action](https://github.com/eclipse-che/che-server/actions?query=workflow%3A%22Release+Che+Server%22) | [`eclipse/che-server`](https://quay.io/eclipse/che-server),
[`eclipse/che-endpoint-watcher`](https://quay.io/eclipse/che-endpoint-watcher),
[`eclipse/che-keycloak`](https://quay.io/eclipse/che-keycloak),
[`eclipse/che-postgres`](https://quay.io/eclipse/che-postgres),
[`eclipse/che-server`](https://quay.io/eclipse/che-server),
[`eclipse/che-e2e`](https://quay.io/eclipse/che-e2e) | -| [che-operator](https://github.com/eclipse-che/che-operator/blob/master/RELEASE.md) | [make-release.sh](https://github.com/eclipse-che/che-operator/blob/master/make-release.sh) | [Action](https://github.com/eclipse-che/che-operator/actions?query=workflow%3A%22Release+Che+Operator%22) | [`eclipse/che-operator`](https://quay.io/eclipse/che-operator)| -| [chectl](https://github.com/che-incubator/chectl/blob/master/RELEASE.md) | [make-release.sh](https://github.com/che-incubator/chectl/blob/master/make-release.sh) | [Action](https://github.com/che-incubator/chectl/actions) | [chectl releases](https://github.com/che-incubator/chectl/releases) +Release can be marked as complete, and this issue can be closed after these steps: +- [ ] check for [remaining version update PRs](https://github.com/eclipse-che/che-release/actions/workflows/release-check-unmerged-PRs.yml) and merge/close them. +- [ ] finalize [release notes](https://github.com/eclipse/che/releases) for this release. [1] Overall process owner: @mkuznyetsov +More information about the process [here](https://github.com/eclipse-che/che-release/blob/main/README.md) diff --git a/.github/ISSUE_TEMPLATE/task.yaml b/.github/ISSUE_TEMPLATE/task.yaml index f6f9c37ae65..e4f6b3380a9 100644 --- a/.github/ISSUE_TEMPLATE/task.yaml +++ b/.github/ISSUE_TEMPLATE/task.yaml @@ -13,11 +13,11 @@ body: Useful Links: - - 📄 Documentation: https://www.eclipse.org/che/docs + - 📄 Documentation: https://eclipse.dev/che/docs - 📝 Contributing: https://github.com/eclipse/che/blob/master/CONTRIBUTING.md 💬 Eclipse Che has public chat on: - - Mattermost: https://mattermost.eclipse.org/eclipse/channels/eclipse-che + - Eclipse Cloud Dev Tools Slack: https://communityinviter.com/apps/ecd-tools/join-the-community - type: textarea id: problem diff --git a/.github/workflows/contributing-repositories-check.yml b/.github/workflows/contributing-repositories-check.yml index 06fd5c135b7..0500486097e 100644 --- a/.github/workflows/contributing-repositories-check.yml +++ b/.github/workflows/contributing-repositories-check.yml @@ -8,7 +8,7 @@ # # Eclipse Che workflow for checking repository list in CONTRIBUTING.md file -name: CI +name: Check repository list in CONTRIBUTING.md file # Trigger the workflow on push or pull request on: diff --git a/.github/workflows/need-triage-label.yaml b/.github/workflows/need-triage-label.yaml new file mode 100644 index 00000000000..4adf0e965c7 --- /dev/null +++ b/.github/workflows/need-triage-label.yaml @@ -0,0 +1,32 @@ +name: Label New Issues + +on: + issues: + types: [opened] + +jobs: + label-issue: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Add Label "status/need-triage" if no label starting with "severity" exists + env: + GITHUB_TOKEN: ${{ secrets.CHE_BOT_GITHUB_TOKEN }} + run: | + ISSUE_NUMBER=${{ github.event.issue.number }} + REPO=${{ github.repository }} + LABEL_TO_ADD="status/need-triage" + LABEL_PREFIX="severity" + # Get the issue labels + ISSUE_LABELS=$(gh issue view $ISSUE_NUMBER --json labels --jq '.labels[].name') + # Check if any label starts with 'severity' + if echo "$ISSUE_LABELS" | grep -q "^$LABEL_PREFIX"; then + echo "A label starting with '$LABEL_PREFIX' exists. No action needed." + else + echo "No label starting with '$LABEL_PREFIX' found. Adding '$LABEL_TO_ADD'." + # Add the label to the issue + gh issue edit $ISSUE_NUMBER --add-label "$LABEL_TO_ADD" + fi diff --git a/.github/workflows/next-build.yml b/.github/workflows/next-build.yml index 0ab7aafb7f7..72c3e4a5449 100644 --- a/.github/workflows/next-build.yml +++ b/.github/workflows/next-build.yml @@ -7,7 +7,7 @@ # SPDX-License-Identifier: EPL-2.0 # -name: build-next +name: Build and push Next Che E2E image to quay.io on: workflow_dispatch: @@ -21,18 +21,6 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - - name: Cache local Maven repository - uses: actions/cache@v3 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - distribution: 'adopt' - java-version: '11' - name: Login to docker.io uses: docker/login-action@v2 with: @@ -59,14 +47,3 @@ jobs: run: | docker push quay.io/eclipse/che-e2e:next docker push quay.io/eclipse/che-e2e:${{ steps.build.outputs.short_sha1 }} - - name: Create failure MM message - if: ${{ failure() }} - run: | - echo "{\"text\":\":no_entry_sign: Next Che E2E build has failed: https://github.com/eclipse/che/actions/workflows/next-build.yml\"}" > mattermost.json - - name: Send MM message - if: ${{ failure() }} - uses: mattermost/action-mattermost-notify@1.1.0 - env: - MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }} - MATTERMOST_CHANNEL: eclipse-che-ci - MATTERMOST_USERNAME: che-bot diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml new file mode 100644 index 00000000000..446c1d6fde5 --- /dev/null +++ b/.github/workflows/pr-check.yml @@ -0,0 +1,177 @@ +# +# Copyright (c) 2021-2023 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# + +#This GitHub Action runs Empty Workspace API test, build Che e2e test container and runs Empty Workspace UI test +#on Che Next deployed on minikube; +#Empty Workspace tests were chosen because of low resource of VM (7RAM, 2CPU, 14Gb disk); +#other cases returned "Insufficient cpu" error + +name: Empty Workspace test suite on minikube + +# Trigger the workflow on pull request +on: + workflow_dispatch: + pull_request: + branches: + - main + - 7.**.x + paths: + - 'tests/e2e/**' + - '.github/workflows/pr-check.yml' +env: + LOCAL_TEST_DIR: /tmp + +jobs: + pr-check: + runs-on: ubuntu-22.04 + + steps: + - name: Git checkout + uses: actions/checkout@v2 + + - name: Branch name + run: | + echo running on PR ${GITHUB_REF}, branch - ${GITHUB_HEAD_REF} + echo "pr_number=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')" >> "$GITHUB_ENV" + docker images + # remove build-in images form the VM becqause it is not used + docker rmi -f $(docker images -aq) + + - name: Configuring nodejs 16.x version + uses: actions/setup-node@v3 + with: + node-version: '16' + + - name: Start minikube + id: run-minikube + uses: che-incubator/setup-minikube-action@next + with: + minikube-version: v1.23.2 + + - name: Install chectl + run: bash <(curl -sL https://che-incubator.github.io/chectl/install.sh) --channel=next + + - name: Deploy Che + run: | + # + # load Che-Code image into minikube + # + minikube image load quay.io/che-incubator/che-code:next + minikube image list + + # get patch file to set up resources + wget https://raw.githubusercontent.com/che-incubator/che-code/main/build/test/github-minikube-checluster-patch.yaml -P /tmp + + # + # deploy Che + # + chectl server:deploy \ + --batch \ + --platform minikube \ + --k8spodwaittimeout=120000 \ + --k8spodreadytimeout=120000 \ + --che-operator-cr-patch-yaml "/tmp/github-minikube-checluster-patch.yaml" + + # + # apply patch + # + kubectl patch devworkspaceoperatorconfigs \ + -n eclipse-che devworkspace-config \ + --patch '{"config": {"workspace": {"imagePullPolicy": "IfNotPresent"}}}' \ + --type merge + + - name: Pull Universal Base Image + run: | + minikube image pull quay.io/devfile/universal-developer-image:ubi8-latest + + - name: Run Empty Workspace API test + run: | + cd tests/e2e + npm ci + export TS_PLATFORM=kubernetes && + export TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL=kubectl && + export TS_SELENIUM_VALUE_OPENSHIFT_OAUTH=false && + export TS_SELENIUM_BASE_URL=https://$(kubectl get ingress che -n eclipse-che -o jsonpath='{.spec.rules[0].host}') && + export NODE_TLS_REJECT_UNAUTHORIZED=0 && + export TS_SELENIUM_LOG_LEVEL=TRACE && + export TS_SELENIUM_DEFAULT_ATTEMPTS=2 && + export USERSTORY=EmptyWorkspaceAPI && + export TS_API_TEST_UDI_IMAGE=quay.io/devfile/universal-developer-image:ubi8-latest && + npm run driver-less-test + + - name: Build E2E test docker image + run: | + # for saving disk space we can remove the assembly folder because it is legacy code + rm -rf assembly + cd tests/e2e + docker build -t quay.io/eclipse/che-e2e:"${{ env.pr_number }}" -f build/dockerfiles/Dockerfile . + + # we have already ran API test, built test image and do not need e2e test-code, remove for saving disk space + - name: Clean up resources + run: | + ls -la ${GITHUB_WORKSPACE} + rm -rf ${GITHUB_WORKSPACE}/che + docker images + + - name: Run Empty Workspace UI test from che-e2e container + run: | + docker run \ + --shm-size=2048m \ + -p 5920:5920 \ + --network="host" \ + -e TS_PLATFORM=kubernetes \ + -e TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL=kubectl \ + -e TS_SELENIUM_K8S_USERNAME=che@eclipse.org \ + -e TS_SELENIUM_K8S_PASSWORD=admin \ + -e TS_SELENIUM_VALUE_OPENSHIFT_OAUTH=false \ + -e TS_SELENIUM_BASE_URL=https://$(kubectl get ingress che -n eclipse-che -o jsonpath='{.spec.rules[0].host}') \ + -e TS_SELENIUM_LOAD_PAGE_TIMEOUT=60000 \ + -e TS_SELENIUM_START_WORKSPACE_TIMEOUT=120000 \ + -e TS_COMMON_DASHBOARD_WAIT_TIMEOUT=30000 \ + -e NODE_TLS_REJECT_UNAUTHORIZED=0 \ + -e DELETE_WORKSPACE_ON_FAILED_TEST=true \ + -e VIDEO_RECORDING=true \ + -e TS_SELENIUM_LOG_LEVEL=TRACE \ + -e TS_SELENIUM_DEFAULT_ATTEMPTS=2 \ + -v ${LOCAL_TEST_DIR}/tests/e2e/report:/tmp/e2e/report:Z \ + -v ${LOCAL_TEST_DIR}/tests/e2e/video:/tmp/ffmpeg_report:Z \ + -e TEST_SUITE=test \ + -e USERSTORY=EmptyWorkspace \ + quay.io/eclipse/che-e2e:"${{ env.pr_number }}" + + - name: Bump logs + if: always() + run: | + NS=admin-che + TARGET_DIR="/tmp/pr-check-artifacts/${NS}-info" + mkdir -p "$TARGET_DIR" + for POD in $(kubectl get pods -o name -n ${NS}); do + for CONTAINER in $(kubectl get -n ${NS} ${POD} -o jsonpath="{.spec.containers[*].name}"); do + echo "[INFO] Downloading logs $POD/$CONTAINER in $NS" + # container name includes `pod/` prefix. remove it + LOGS_FILE=$TARGET_DIR/$(echo ${POD}-${CONTAINER}.log | sed 's|pod/||g') + kubectl logs ${POD} -c ${CONTAINER} -n ${NS} > $LOGS_FILE || true + done + done + echo "[INFO] Bumping events in namespace ${NS}" + kubectl get events -n $NS > $TARGET_DIR/events.log || true + + - name: Store e2e artifacts + if: always() + uses: actions/upload-artifact@v3 + with: + name: e2e-artifacts + path: /tmp/tests + + - name: Store k8s logs + if: always() + uses: actions/upload-artifact@v3 + with: + name: k8s-logs + path: /tmp/pr-check-artifacts/admin-che-info diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e1ada879c8..28b7c72a64b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -106,17 +106,17 @@ jobs: pushd tests/e2e >/dev/null || exit npm ci && npm run tsc && npm publish popd >/dev/null || exit - - name: Create failure MM message - if: ${{ failure() }} - run: | - echo "{\"text\":\":no_entry_sign: Che E2E Tests ${{ github.event.inputs.version }} release has failed: https://github.com/eclipse/che/actions/workflows/release.yml\"}" > mattermost.json - - name: Create success MM message - run: | - echo "{\"text\":\":white_check_mark: Che E2E Tests image and generator ${{ github.event.inputs.version }} release job is complete: \n Performed tagging and container build of new image: https://quay.io/eclipse/che-e2e:${{ github.event.inputs.version }}. \n Published package to npmjs https://www.npmjs.com/package/@eclipse-che/che-e2e/v/${{ github.event.inputs.version }}.\"}" > mattermost.json - - name: Send MM message - if: ${{ success() }} || ${{ failure() }} - uses: mattermost/action-mattermost-notify@1.1.0 - env: - MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }} - MATTERMOST_CHANNEL: eclipse-che-releases - MATTERMOST_USERNAME: che-bot + #- name: Create failure MM message + #if: ${{ failure() }} + #run: | + #echo "{\"text\":\":no_entry_sign: Che E2E Tests ${{ github.event.inputs.version }} release has failed: https://github.com/eclipse/che/actions/workflows/release.yml\"}" > mattermost.json + #- name: Create success MM message + #run: | + #echo "{\"text\":\":white_check_mark: Che E2E Tests image and generator ${{ github.event.inputs.version }} release job is complete: \n Performed tagging and container build of new image: https://quay.io/eclipse/che-e2e:${{ github.event.inputs.version }}. \n Published package to npmjs https://www.npmjs.com/package/@eclipse-che/che-e2e/v/${{ github.event.inputs.version }}.\"}" > mattermost.json + #- name: Send MM message + #if: ${{ success() }} || ${{ failure() }} + #uses: mattermost/action-mattermost-notify@1.1.0 + #env: + #MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }} + #MATTERMOST_CHANNEL: eclipse-che-releases + #MATTERMOST_USERNAME: che-bot diff --git a/.github/workflows/typescript-publish.yml b/.github/workflows/typescript-publish.yml index 495dc126912..15c5e9ec177 100644 --- a/.github/workflows/typescript-publish.yml +++ b/.github/workflows/typescript-publish.yml @@ -7,7 +7,7 @@ # SPDX-License-Identifier: EPL-2.0 # -name: typescript-publish-next +name: Publish Next Che E2E Tests to npmjs on: workflow_dispatch: @@ -48,8 +48,8 @@ jobs: npm ci && npm run tsc SHORT_SHA1=$(git rev-parse --short=7 HEAD) - CURRENT_VERSION=$(sed -r 's/(.*)-SNAPSHOT/\1/' ../../VERSION) - NEW_VERSION="${CURRENT_VERSION}-dev-${SHORT_SHA1}" + CURRENT_VERSION=$(sed -r 's/(.*)-next/\1/' ../../VERSION) + NEW_VERSION="${CURRENT_VERSION}-next-${SHORT_SHA1}" sed -i -r -e "s/(\"version\": )(\".*\")/\1\"$NEW_VERSION\"/" package.json npm publish --tag $DIST_TAG diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000000..6b114c6b30e --- /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 tsc && npm run prettier diff --git a/.repositories-update-contributing.sh b/.repositories-update-contributing.sh index da53d0b5ded..fc8c850007c 100755 --- a/.repositories-update-contributing.sh +++ b/.repositories-update-contributing.sh @@ -14,7 +14,7 @@ set -e set -u -YQ_IMAGE="mikefarah/yq:3.3.2" +YQ_IMAGE="docker.io/mikefarah/yq:3.3.2" DIR=$(cd "$(dirname "$0")"; pwd) diff --git a/.repositories.yaml b/.repositories.yaml index 54ad5e52209..00a742314bc 100644 --- a/.repositories.yaml +++ b/.repositories.yaml @@ -13,7 +13,7 @@ repositories: description: >- (this repository) the main project repository devfile: https://github.com/eclipse/che/blob/main/devfile.yaml - doc: https://github.com/eclipse/che/blob/main/CONTRIBUTING.md#che-server-aka-ws-master + doc: https://github.com/eclipse/che/blob/main/CONTRIBUTING.md useCheReleaseLifecycle: true components: - name: tests @@ -25,40 +25,27 @@ repositories: description: >- Che server project repository devfile: https://github.com/eclipse-che/che-server/blob/HEAD/devfile.yaml - doc: https://github.com/eclipse/che/blob/HEAD/CONTRIBUTING.md#che-server-aka-ws-master + doc: https://github.com/eclipse/che/blob/HEAD/CONTRIBUTING.md useCheReleaseLifecycle: true components: - name: dockerfiles url: https://github.com/eclipse-che/che-server/tree/HEAD/dockerfiles description: >- - source code, dockerfiles to build our main docker images. Note that Che-theia related dockerfiles are located in che-theia repo. + source code, dockerfiles to build our main docker images. Note that Che-code related dockerfiles are located in che-code repo. - name: che-server url: https://github.com/eclipse-che/che-server/tree/HEAD/wsmaster description: >- orchestrates the Che workspaces with devfiles on Kubernetes - name: tests - url: https://github.com/eclipse/che/tree/master/tests + url: https://github.com/eclipse/che/tree/main/tests description: >- source code of our integration tests. - - url: https://github.com/eclipse-che/che-theia - name: che-theia - description: >- - Theia IDE integrated in Che. - devfile: https://github.com/eclipse-che/che-theia/blob/main/devfiles/che-theia-all.devfile.yaml - doc: https://github.com/eclipse-che/che-theia/blob/main/CONTRIBUTING.md - useCheReleaseLifecycle: true - components: - - name: generator - url: https://github.com/eclipse-che/che-theia/tree/main/generator - description: >- - `che:theia init` CLI to prepare and build che-theia - doc: https://github.com/eclipse-che/che-theia/blob/main/generator/CONTRIBUTING.md - url: https://github.com/che-incubator/chectl name: chectl description: >- The CLI to install Che, create and start workspaces and devfiles - devfile: https://github.com/che-incubator/chectl/blob/master/devfile.yaml - doc: https://github.com/che-incubator/chectl/blob/master/CONTRIBUTING.md + devfile: https://github.com/che-incubator/chectl/blob/main/devfile.yaml + doc: https://github.com/che-incubator/chectl/blob/main/CONTRIBUTING.md useCheReleaseLifecycle: true - url: https://github.com/che-incubator/che-code name: che-code @@ -90,22 +77,15 @@ repositories: name: machine-exec description: >- Interface to execute tasks and terminals on other containers within a workspace. - devfile: https://github.com/eclipse-che/che-machine-exec/blob/master/devfile.yaml - doc: https://github.com/eclipse-che/che-machine-exec/blob/master/CONTRIBUTING.md + devfile: https://github.com/eclipse-che/che-machine-exec/blob/main/devfile.yaml + doc: https://github.com/eclipse-che/che-machine-exec/blob/main/CONTRIBUTING.md useCheReleaseLifecycle: true - url: https://github.com/eclipse-che/che-operator name: operator description: >- Che operator to deploy, update and manage K8S/OpenShift resources of Che. - devfile: https://github.com/eclipse-che/che-operator/blob/master/devfile.yaml + devfile: https://github.com/eclipse-che/che-operator/blob/main/devfile.yaml useCheReleaseLifecycle: true - - url: https://github.com/eclipse-che/che-plugin-broker - name: plugin-broker - description: >- - The workspace microservice that is in charge of analyzing, preparing and installing the workspace components defined in a Devfile. - devfile: https://github.com/eclipse-che/che-plugin-broker/blob/master/devfile.yaml - doc: https://github.com/eclipse-che/che-plugin-broker/blob/master/CONTRIBUTING.md - useCheReleaseLifecycle: false - url: https://github.com/eclipse-che/che-plugin-registry name: plugin-registry description: >- @@ -114,7 +94,7 @@ repositories: - url: https://github.com/eclipse-che/che-website name: website description: >- - https://eclipse.org/che website source code. + https://eclipse.dev/che website source code. devfile: https://github.com/eclipse-che/che-website/blob/main/.devfile.yaml useCheReleaseLifecycle: false - url: https://github.com/eclipse-che/che-workspace-client @@ -238,8 +218,3 @@ repositories: description: >- Devfile API library useCheReleaseLifecycle: false - - url: https://github.com/che-incubator/devfile-api - name: devfile-api - description: >- - Devfile API library - useCheReleaseLifecycle: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 871a515d983..42d1876b5b0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,34 +16,22 @@ If creating a new repo under the [eclipse-che](https://github.com/eclipse-che) o Repository | Component | Description | Devfile | Documentation --- | --- | --- | --- | --- -[che](https://github.com/eclipse/che) | | (this repository) the main project repository | [devfile](https://github.com/eclipse/che/blob/main/devfile.yaml) | [doc](https://github.com/eclipse/che/blob/main/CONTRIBUTING.md#che-server-aka-ws-master) +[che](https://github.com/eclipse/che) | | (this repository) the main project repository | [devfile](https://github.com/eclipse/che/blob/main/devfile.yaml) | [doc](https://github.com/eclipse/che/blob/main/CONTRIBUTING.md) ---| [tests](https://github.com/eclipse/che/tree/main/tests) | source code of our integration tests. | | | -[che-server](https://github.com/eclipse-che/che-server/) | | Che server project repository | [devfile](https://github.com/eclipse-che/che-server/blob/HEAD/devfile.yaml) | [doc](https://github.com/eclipse/che/blob/HEAD/CONTRIBUTING.md#che-server-aka-ws-master) ----| [dockerfiles](https://github.com/eclipse-che/che-server/tree/HEAD/dockerfiles) | source code, dockerfiles to build our main docker images. Note that Che-theia related dockerfiles are located in che-theia repo. | | | +[che-server](https://github.com/eclipse-che/che-server/) | | Che server project repository | [devfile](https://github.com/eclipse-che/che-server/blob/HEAD/devfile.yaml) | [doc](https://github.com/eclipse/che/blob/HEAD/CONTRIBUTING.md) +---| [dockerfiles](https://github.com/eclipse-che/che-server/tree/HEAD/dockerfiles) | source code, dockerfiles to build our main docker images. Note that Che-code related dockerfiles are located in che-code repo. | | | ---| [che-server](https://github.com/eclipse-che/che-server/tree/HEAD/wsmaster) | orchestrates the Che workspaces with devfiles on Kubernetes | | | ----| [tests](https://github.com/eclipse/che/tree/master/tests) | source code of our integration tests. | | | -[che-theia](https://github.com/eclipse-che/che-theia) | | Theia IDE integrated in Che. | [devfile](https://github.com/eclipse-che/che-theia/blob/main/devfiles/che-theia-all.devfile.yaml) | [doc](https://github.com/eclipse-che/che-theia/blob/main/CONTRIBUTING.md) ----| [generator](https://github.com/eclipse-che/che-theia/tree/main/generator) | `che:theia init` CLI to prepare and build che-theia | | | -[chectl](https://github.com/che-incubator/chectl) | | The CLI to install Che, create and start workspaces and devfiles | [devfile](https://github.com/che-incubator/chectl/blob/master/devfile.yaml) | [doc](https://github.com/che-incubator/chectl/blob/master/CONTRIBUTING.md) +---| [tests](https://github.com/eclipse/che/tree/main/tests) | source code of our integration tests. | | | +[chectl](https://github.com/che-incubator/chectl) | | The CLI to install Che, create and start workspaces and devfiles | [devfile](https://github.com/che-incubator/chectl/blob/main/devfile.yaml) | [doc](https://github.com/che-incubator/chectl/blob/main/CONTRIBUTING.md) [che-code](https://github.com/che-incubator/che-code) | | Fork of "Code - OSS" to work with Eclipse Che | [devfile](https://github.com/che-incubator/che-code/blob/main/devfile.yaml) | [doc](https://github.com/che-incubator/che-code/blob/main/README.md) [dashboard](https://github.com/eclipse-che/che-dashboard) | | UI to manage workspaces, devfiles, etc. | [devfile](https://github.com/eclipse-che/che-dashboard/blob/main/devfile.yaml) | [doc](https://github.com/eclipse-che/che-dashboard/blob/main/README.md#eclipse-che-dashboard) [devfile-registry](https://github.com/eclipse-che/che-devfile-registry) | | The default set of devfiles that would be made available on the Che dashboard stacks. | | [docs](https://github.com/eclipse-che/che-docs) | | Eclipse Che documentation https://github.com/eclipse-che/che-docs source code. | [devfile](https://github.com/eclipse-che/che-docs/blob/main/devfile.yaml) | [doc](https://github.com/eclipse-che/che-docs/blob/main/CONTRIBUTING.adoc) -[machine-exec](https://github.com/eclipse-che/che-machine-exec) | | Interface to execute tasks and terminals on other containers within a workspace. | [devfile](https://github.com/eclipse-che/che-machine-exec/blob/master/devfile.yaml) | [doc](https://github.com/eclipse-che/che-machine-exec/blob/master/CONTRIBUTING.md) -[operator](https://github.com/eclipse-che/che-operator) | | Che operator to deploy, update and manage K8S/OpenShift resources of Che. | [devfile](https://github.com/eclipse-che/che-operator/blob/master/devfile.yaml) | -[plugin-broker](https://github.com/eclipse-che/che-plugin-broker) | | The workspace microservice that is in charge of analyzing, preparing and installing the workspace components defined in a Devfile. | [devfile](https://github.com/eclipse-che/che-plugin-broker/blob/master/devfile.yaml) | [doc](https://github.com/eclipse-che/che-plugin-broker/blob/master/CONTRIBUTING.md) +[machine-exec](https://github.com/eclipse-che/che-machine-exec) | | Interface to execute tasks and terminals on other containers within a workspace. | [devfile](https://github.com/eclipse-che/che-machine-exec/blob/main/devfile.yaml) | [doc](https://github.com/eclipse-che/che-machine-exec/blob/main/CONTRIBUTING.md) +[operator](https://github.com/eclipse-che/che-operator) | | Che operator to deploy, update and manage K8S/OpenShift resources of Che. | [devfile](https://github.com/eclipse-che/che-operator/blob/main/devfile.yaml) | [plugin-registry](https://github.com/eclipse-che/che-plugin-registry) | | The default set of Che plugins (vscode extension + containers) or editors that could be installed on any Che workspaces. | | -[website](https://github.com/eclipse-che/che-website) | | https://eclipse.org/che website source code. | [devfile](https://github.com/eclipse-che/che-website/blob/main/.devfile.yaml) | +[website](https://github.com/eclipse-che/che-website) | | https://eclipse.dev/che website source code. | [devfile](https://github.com/eclipse-che/che-website/blob/main/.devfile.yaml) | [workspace-client](https://github.com/eclipse-che/che-workspace-client) | | JS library to interact with a che-server. | | -[che-container-tools](https://github.com/che-dockerfiles/che-container-tools) | | Base image used for sidecars that service container tooling plugins | | -[che-custom-nodejs-deasync](https://github.com/che-dockerfiles/che-custom-nodejs-deasync) | | Provides a custom nodejs binary embedding deasync node-gyp module as builtin module | | -[che-cert-manager-ca-cert-generator-image](https://github.com/che-dockerfiles/che-cert-manager-ca-cert-generator-image) | | CA cert generation job image used by chectl | | -[che-buildkit-base](https://github.com/che-dockerfiles/che-buildkit-base) | | Eclipse Che Sidecar container for buildkit tooling | | -[che-buildah-base](https://github.com/che-dockerfiles/che-buildah-base) | | Use this image to build docker images using buildah | | -[che-docker-registry-image-copier](https://github.com/che-dockerfiles/che-docker-registry-image-copier) | | copy images between public and private docker registry inside k8s cluster | | -[che-php-base](https://github.com/che-dockerfiles/che-php-base) | | Base image to be used for the PHP devfile | | -[che-tls-secret-creator](https://github.com/che-dockerfiles/che-tls-secret-creator) | | This images generates TLS certificates | | -[che-theia-openshift-auth](https://github.com/che-incubator/che-theia-openshift-auth) | | OpenShift authentication plugin | | [configbump](https://github.com/che-incubator/configbump) | | Simple Kubernetes controller that is able to quickly synchronize a set of config maps | | [workspace-data-sync](https://github.com/che-incubator/workspace-data-sync) | | Provides the ability to increase I/O performance for a developer workspaces | | [che-workspace-telemetry-client](https://github.com/che-incubator/che-workspace-telemetry-client) | | abstract telemetry API and a Typescript implementation of the API. | | @@ -61,7 +49,12 @@ Repository | Component | Description | Devfile | Documentation [registry](https://github.com/devfile/registry) | | Upstream devfile registry | | [developer-images](https://github.com/devfile/developer-images) | | Container images to code, build run applications on secured Kubernetes clusters | | [devworkspace-operator-docs](https://github.com/devfile/devworkspace-operator-docs) | | DevWorkspace operator documentation | | -[git-srv](https://github.com/che-incubator/git-srv) | | Scripts to deploy oAuth supported self-hosted git providers | | +[check-license-header](https://github.com/che-incubator/check-license-header) | | License header format checker | | +[devworkspace-telemetry-woopra-plugin](https://github.com/che-incubator/devworkspace-telemetry-woopra-plugin) | | Devworkspace telemetry Woopra plugin | | +[setup-minikube-action](https://github.com/che-incubator/setup-minikube-action) | | Github action for starting Minikube to be able to Install/Run Eclipse Che | | +[dependencies-license-action](https://github.com/che-incubator/dependencies-license-action) | | Github action to check file with list golang runtime dependencies and license information. | | +[dash-licenses](https://github.com/che-incubator/dash-licenses) | | A container wrapper for The Eclipse Dash License Tool. | | +[devfile-api](https://github.com/che-incubator/devfile-api) | | Devfile API library | | ## Devfile to contribute diff --git a/README.md b/README.md index e2f3645428e..d151163e743 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,18 @@ -[![Dev](https://img.shields.io/static/v1?label=Open%20in&message=Che%20dogfooding%20server%20(with%20VS%20Code)&logo=eclipseche&color=FDB940&labelColor=525C86)](https://che-dogfooding.apps.che-dev.x6e0.p1.openshiftapps.com/#https://github.com/eclipse/che?che-editor=che-incubator/che-code/insiders) -[![Dev](https://img.shields.io/static/v1?label=Open%20in&message=Che%20dogfooding%20server%20(with%20Theia)&logo=eclipseche&color=FDB940&labelColor=525C86)](https://che-dogfooding.apps.che-dev.x6e0.p1.openshiftapps.com/#https://github.com/eclipse/che?che-editor=eclipse/che-theia/next) - -### Eclipse Che Server has moved! - -If you're looking for the sources of the Eclipse Che Server, it has been relocated here: - -https://github.com/eclipse-che/che-server - - @@ -28,7 +20,7 @@ https://www.eclipse.org/che/) --- -**Visit website at: https://www.eclipse.org/che/** and documentation at: https://www.eclipse.org/che/docs +**Visit website at: https://eclipse.dev/che/** and documentation at: https://eclipse.dev/che/docs - [**Getting Started**](#getting-started) - [**Using Eclipse Che**](#using-eclipse-che) @@ -41,22 +33,23 @@ https://www.eclipse.org/che/) ### Getting Started Here you can find links on how to get started with Eclipse Che: -- [Use Eclipse Che online](https://www.eclipse.org/che/getting-started/cloud/) -- [Run Eclipse Che on your own K8S cluster](https://www.eclipse.org/che/docs/che-7/che-quick-starts) +- [Use Eclipse Che online](https://eclipse.dev/che/getting-started/cloud/) +- [Run Eclipse Che on your own Kubernetes cluster](https://eclipse.dev/che/docs/stable/administration-guide/preparing-the-installation/) ### Using Eclipse Che Here you can find references to useful documentation and hands-on guides to learn how to get the most of Eclipse Che: -- [Customize Che workspaces for your projects](https://www.eclipse.org/che/docs/che-7/configuring-a-workspace-using-a-devfile/) -- [Run VSCode Extensions in Che workspaces](https://www.eclipse.org/che/docs/che-7/end-user-guide/adding-a-vs-code-extension-to-a-workspace/) -- [Creating and configuring a new Che 7 workspace](https://www.eclipse.org/che/docs/che-7/end-user-guide/creating-and-configuring-a-new-workspace/) -- [Making a workspace portable using a devfile](https://www.eclipse.org/che/docs/che-7/end-user-guide/making-a-workspace-portable-using-a-devfile/) - +- [Customize Che workspaces for your projects](https://eclipse.dev/che/docs/stable/end-user-guide/customizing-workspace-components/) +- [Automatically run VSCode Extensions in Che workspaces](https://eclipse.dev/che/docs/stable/end-user-guide/microsoft-visual-studio-code-open-source-ide/#automating-installation-of-microsoft-visual-studio-code-extensions-at-workspace-startup) +- [Starting a workspace from a Git repository URL](https://eclipse.dev/che/docs/stable/end-user-guide/starting-a-workspace-from-a-git-repository-url/) +- [Making a workspace portable using a devfile](https://eclipse.dev/che/docs/stable/end-user-guide/devfile-introduction/) +- [Configure your instance of Che](https://eclipse.dev/che/docs/stable/administration-guide/checluster-custom-resource-fields-reference/) using the [CheCluster Kubernetes Custom Resource](https://doc.crds.dev/github.com/eclipse-che/che-operator) +- [Use and customize the embedded VSCode extensions registry.](https://eclipse.dev/che/docs/stable/administration-guide/extensions-for-microsoft-visual-studio-code-open-source/#adding-or-removing-extensions-in-the-embedded-open-vsx-registry-instance) ### Feedback and Community We love to hear from users and developers. Here are the various ways to get in touch with us: * **Support:** You can ask questions, report bugs, and request features using [GitHub issues](https://github.com/eclipse/che/issues). -* **Public Chat:** Join the public [eclipse-che](https://mattermost.eclipse.org/eclipse/channels/eclipse-che) Mattermost channel to discuss with community and contributors. +* **Public Chat:** Join the public [eclipse-che](https://communityinviter.com/apps/ecd-tools/join-the-community) Mattermost channel to discuss with community and contributors. * **Twitter:** [@eclipse_che](https://twitter.com/eclipse_che) * **Mailing List:** [che-dev@eclipse.org](https://accounts.eclipse.org/mailing-list/che-dev) * **Weekly Meetings:** Join us in our [Che community meeting](https://github.com/eclipse/che/wiki/Che-Dev-Meetings) every second monday. @@ -67,21 +60,19 @@ If you are interested in fixing issues and contributing directly to the code bas - :bug: [Submitting bugs](https://github.com/eclipse/che/issues/new/choose) - :page_facing_up: [Contributor license agreement](https://github.com/eclipse/che/wiki/Eclipse-Contributor-Agreement) - :checkered_flag: [Development workflows](./CONTRIBUTING.md) -- :ok_hand: [Review source code changes](https://github.com/eclipse/che/pulls) -- :pencil: [Improve docs](https://github.com/eclipse/che-docs) -- :building_construction: [Che architecture](https://www.eclipse.org/che/docs/che-7/administration-guide/che-architecture-overview/) +- :pencil: [Improve docs](https://github.com/eclipse-che/che-docs) +- :building_construction: [Che architecture](https://eclipse.dev/che/docs/stable/administration-guide/architecture-overview/) - :octocat: [Che repositories](./CONTRIBUTING.md#other-che-repositories) - :sparkles: [Good first issue for new contributors](https://github.com/eclipse/che/wiki/Labels#new-contributors) #### Extending Eclipse Che -- [Add a new language support. (to be provided soon)](https://www.eclipse.org/che/docs/che-7/adding-support-for-a-new-language/) -- [Package your favorite VSCode extensions and make them available in Che.](https://www.eclipse.org/che/docs/che-7/end-user-guide/publishing-metadata-for-a-vs-code-extension/) -- [Write your own VSCode extension that runs on a dedicated side car container.](https://www.eclipse.org/che/docs/che-7/what-is-a-che-theia-plug-in/) -- [Build and package your custom Che-Theia editor with your extensions and plugins.](https://www.eclipse.org/che/docs/che-7/using-alternative-ides-in-che/) +- [Customize the default dev tooling container (the universal developer image or UDI).](https://github.com/devfile/developer-images/) +- [Customize the list of getting started samples.](https://eclipse.dev/che/docs/stable/administration-guide/configuring-getting-started-samples/) +- [Add your own editor definition.](https://github.com/eclipse-che/che-plugin-registry/blob/main/che-editors.yaml) ### Roadmap We maintain the [Che roadmap](https://github.com/eclipse/che/wiki/Roadmap) in the open way. We welcome anyone to ask question and contribute to the roadmap by joining our [community meetings](https://github.com/eclipse/che/wiki/Che-Dev-Meetings). ### License -Che is open sourced under the Eclipse Public License 2.0. +Eclipse Public License 2.0. diff --git a/VERSION b/VERSION index ddfc82bf6f8..636d0f6c78b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.72.0-SNAPSHOT +7.91.0-next diff --git a/VERSION.orig b/VERSION.orig new file mode 100644 index 00000000000..e8ff06fa1a1 --- /dev/null +++ b/VERSION.orig @@ -0,0 +1,5 @@ +<<<<<<< HEAD +7.72.0-SNAPSHOT +======= +7.91.0-next +>>>>>>> main diff --git a/make-release.sh b/make-release.sh index 98807050246..2aaf25cb7be 100755 --- a/make-release.sh +++ b/make-release.sh @@ -39,7 +39,7 @@ update_issue_template() { local -r templateFile=$2 # take only two first digits of the version that we will release - # will get 7.35 from input 7.35.0-SNAPSHOT + # will get 7.74 from input 7.74.0-next local -r versionXY=$(echo "${currentReleaseVersion}" | sed -ne 's/[^0-9]*\(\([0-9]\.\)\{0,4\}[0-9][^.]\).*/\1/p') # now extract the current latest version specified in the issue template @@ -76,7 +76,12 @@ bump_version () { pushd tests/e2e >/dev/null || exit npm --no-git-tag-version version --allow-same-version "${NEXT_VERSION}" - sed_in_place -r -e "/@eclipse-che\/api|@eclipse-che\/workspace-client|@eclipse-che\/workspace-telemetry-client|@eclipse-che\/che-devworkspace-generator/!s/(\"@eclipse-che\/..*\": )(\".*\")/\1\"$VERSION\"/" package.json + # update devworkspace generator version only for bugfix releases (e.g. for 7.74.x branch, version would be next-7.74.x) + if [[ "${BASEBRANCH}" == "${BRANCH}" ]]; then + jq ".\"dependencies\".\"@eclipse-che/che-devworkspace-generator\" = \"next-${BRANCH}\"" package.json > package.json.update + mv package.json.update package.json + fi + npm run prettier popd >/dev/null || exit COMMIT_MSG="chore: Bump to ${NEXT_VERSION} in ${BUMP_BRANCH}" @@ -94,7 +99,7 @@ bump_version () { git pull origin "${PR_BRANCH}" git push origin "${PR_BRANCH}" lastCommitComment="$(git log -1 --pretty=%B)" - hub pull-request -f -m "${lastCommitComment}" -b "${BUMP_BRANCH}" -h "${PR_BRANCH}" + gh pr create -f -B "${BUMP_BRANCH}" -H "${PR_BRANCH}" fi set -e git checkout "${CURRENT_BRANCH}" @@ -154,8 +159,12 @@ set -e echo "${VERSION}" > VERSION pushd tests/e2e >/dev/null || exit -sed_in_place -r -e "/@eclipse-che\/api|@eclipse-che\/workspace-client|@eclipse-che\/workspace-telemetry-client|@eclipse-che\/che-devworkspace-generator/!s/(\"@eclipse-che\/..*\": )(\".*\")/\1\"$VERSION\"/" package.json +# update devworkspace generator version +jq ".\"dependencies\".\"@eclipse-che/che-devworkspace-generator\" = \"${VERSION}\"" package.json > package.json.update +mv package.json.update package.json +npm i -g prettier npm --no-git-tag-version version --allow-same-version "${VERSION}" +npm run prettier popd >/dev/null || exit docker build -t quay.io/eclipse/che-e2e:${VERSION} -f tests/e2e/build/dockerfiles/Dockerfile tests/e2e @@ -173,9 +182,7 @@ git commit -asm "${COMMIT_MSG}" git tag "${VERSION}" git push origin "${VERSION}" - - -# now update ${BASEBRANCH} to the new snapshot version +# now update ${BASEBRANCH} to the new next version git checkout "${BASEBRANCH}" # update template in the branch @@ -185,12 +192,12 @@ update_issue_template "${VERSION}" "${ISSUE_TEMPLATE_FILE}" if [[ "${BASEBRANCH}" != "${BRANCH}" ]]; then # bump the y digit, if it is a major release [[ $BRANCH =~ ^([0-9]+)\.([0-9]+)\.x ]] && BASE=${BASH_REMATCH[1]}; NEXT=${BASH_REMATCH[2]}; (( NEXT=NEXT+1 )) # for BRANCH=0.1.x, get BASE=0, NEXT=2 - NEXT_VERSION_Y="${BASE}.${NEXT}.0-SNAPSHOT" + NEXT_VERSION_Y="${BASE}.${NEXT}.0-next" bump_version "${NEXT_VERSION_Y}" "${BASEBRANCH}" fi # bump the z digit [[ ${VERSION#v} =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]] && BASE="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"; NEXT="${BASH_REMATCH[3]}"; (( NEXT=NEXT+1 )) # for VERSION=0.1.2, get BASE=0.1, NEXT=3 -NEXT_VERSION_Z="${BASE}.${NEXT}-SNAPSHOT" +NEXT_VERSION_Z="${BASE}.${NEXT}-next" bump_version "${NEXT_VERSION_Z}" "${BRANCH}" # cleanup tmp dir diff --git a/tests/devworkspace-happy-path/launch.sh b/tests/devworkspace-happy-path/launch.sh index 90a3b7f4e84..98a48c7755a 100755 --- a/tests/devworkspace-happy-path/launch.sh +++ b/tests/devworkspace-happy-path/launch.sh @@ -20,138 +20,16 @@ set -u START=$(date +%s.%N) SCRIPT_DIR=$(dirname $(readlink -f "$0")) -export WORKDIR="${WORKDIR:-${SCRIPT_DIR}/workdir}" export CHE_NAMESPACE="${CHE_NAMESPACE:-eclipse-che}" -export E2E_TEST_IMAGE="${E2E_TEST_IMAGE:-quay.io/eclipse/che-e2e:next}" export HAPPY_PATH_POD_NAME=happy-path-che -export HAPPY_PATH_TEST_PROJECT='https://github.com/che-samples/java-spring-petclinic/tree/devfilev2' -export HAPPY_PATH_SUITE="${HAPPY_PATH_SUITE:-test-all-devfiles}" -export HAPPY_PATH_USERSTORY="${HAPPY_PATH_USERSTORY:-EmptyWorkspace}" -rm -rf ${WORKDIR} -mkdir -p ${WORKDIR} +source "${SCRIPT_DIR}/common.sh" -# Create cluster-admin user inside of OpenShift cluster and login -function provisionOpenShiftOAuthUser() { - echo "[INFO] Testing if Che User exists." - KUBECONFIG="${KUBECONFIG:-${HOME}/.kube/config}" - TMP_KUBECONFIG="$WORKDIR/kubeconfig" - cp "$KUBECONFIG" "$TMP_KUBECONFIG" - - if oc login -u che-user -p user --kubeconfig $TMP_KUBECONFIG; then - echo "[INFO] Che User already exists. Using it" - return 0 - fi - echo "[INFO] Che User does not exist. Setting up htpasswd oauth for it." - oc delete secret dev-htpasswd-secret -n openshift-config || true - oc create secret generic dev-htpasswd-secret --from-file=htpasswd="$SCRIPT_DIR/resources/users.htpasswd" -n openshift-config - - if [[ $(oc get oauth cluster --ignore-not-found) == "" ]]; then - echo "[INFO] Creating a new OAuth Cluster since it's not found." - oc apply -f ${SCRIPT_DIR}/resources/cluster-oauth.yaml - # CustomResources don't support strategic merge. So, we need to merge or add array item depending on the object state - elif [[ $(oc get oauth/cluster -o=json | jq -e 'select (.spec.identityProviders == null)') ]]; then - # there are no identity providers. We can do merge and set the whole .spec.identityProviders field - echo "[INFO] No identity providers found, provisioning Che one." - oc patch oauth/cluster --type=merge -p "$(cat $SCRIPT_DIR/resources/cluster-oauth-patch.json)" - elif [[ ! $(oc get oauth/cluster -o=json | jq -e '.spec.identityProviders[]?.name? | select ( . == ("dev-htpasswd"))') ]]; then - # there are some identity providers. We should do add patch not to override existing identity providers - echo "[INFO] OAuth Cluster is found but dev-htpasswd provider missing. Provisioning it." - oc patch oauth/cluster --type=json -p '[{ - "op": "add", - "path": "/spec/identityProviders/0", - "value": { - "name":"dev-htpasswd", - "mappingMethod":"add", - "type":"HTPasswd", - "htpasswd": { - "fileData":{"name":"dev-htpasswd-secret"} - } - } - }]' - - else - echo "[INFO] dev-htpasswd oauth provider is found. Using it" - fi - - echo "[INFO] rollout oauth-openshift pods for applying OAuth configuration" - # apply just added identity providers, we need to rollout deployment for make sure - # that new IDP item will appear in the IDP table - # https://github.com/eclipse/che/issues/20822 - - oc rollout status -n openshift-authentication deployment/oauth-openshift - echo -e "[INFO] Waiting for htpasswd auth to be working up to 5 minutes" - CURRENT_TIME=$(date +%s) - ENDTIME=$(($CURRENT_TIME + 300)) - while [ $(date +%s) -lt $ENDTIME ]; do - if oc login -u happypath-dev -p dev --kubeconfig $TMP_KUBECONFIG; then - return 0 - fi - sleep 10 - done - echo "[ERROR] Che htpasswd changes are not affected after timeout." - exit 1 -} - -startHappyPathTest() { - oc delete pod happy-path-che -n eclipse-che --grace-period=30 --ignore-not-found - # patch happy-path-che.yaml - ECLIPSE_CHE_URL=http://$(oc get route -n "${CHE_NAMESPACE}" che -o jsonpath='{.status.ingress[0].host}') - TS_SELENIUM_DEVWORKSPACE_URL="${ECLIPSE_CHE_URL}/#${HAPPY_PATH_TEST_PROJECT}" - HAPPY_PATH_POD_FILE=${SCRIPT_DIR}/resources/pod-che-happy-path.yaml - cp $HAPPY_PATH_POD_FILE ${WORKDIR}/e2e-pod.yaml - sed -i "s@HAPPY_PATH_SUITE@${HAPPY_PATH_SUITE}@g" ${WORKDIR}/e2e-pod.yaml - sed -i "s@HAPPY_PATH_USERSTORY@${HAPPY_PATH_USERSTORY}@g" ${WORKDIR}/e2e-pod.yaml - sed -i "s@CHE_URL@${ECLIPSE_CHE_URL}@g" ${WORKDIR}/e2e-pod.yaml - sed -i "s@WORKSPACE_ROUTE@${TS_SELENIUM_DEVWORKSPACE_URL}@g" ${WORKDIR}/e2e-pod.yaml - sed -i "s@CHE-NAMESPACE@${CHE_NAMESPACE}@g" ${WORKDIR}/e2e-pod.yaml - sed -i "s@image: .*@image: ${E2E_TEST_IMAGE}@g" ${WORKDIR}/e2e-pod.yaml - echo "[INFO] Applying the following patched Che Happy Path Pod:" - cat ${WORKDIR}/e2e-pod.yaml - echo "[INFO] --------------------------------------------------" - oc apply -f ${WORKDIR}/e2e-pod.yaml - # wait for the pod to start - n=0 - while [ $n -le 120 ] - do - PHASE=$(oc get pod -n ${CHE_NAMESPACE} ${HAPPY_PATH_POD_NAME} \ - --template='{{ .status.phase }}') - if [[ ${PHASE} == "Running" ]]; then - echo "[INFO] Happy-path test started successfully." - return - fi - - sleep 5 - n=$(( n+1 )) - done - - echo "[ERROR] Failed to start happy-path test." - exit 1 -} - -provisionOpenShiftOAuthUser - -source "${SCRIPT_DIR}"/common.sh # Catch the finish of the job and write logs in artifacts. trap 'collectLogs $?' EXIT SIGINT -startHappyPathTest - -echo "[INFO] Waiting until happy path pod finished" -oc logs -n ${CHE_NAMESPACE} ${HAPPY_PATH_POD_NAME} -c happy-path-test -f -# just to sleep -sleep 3 - -echo "[INFO] Downloading test report." -mkdir ${ARTIFACT_DIR}/e2e -oc rsync -n ${CHE_NAMESPACE} ${HAPPY_PATH_POD_NAME}:/tmp/e2e/report/ ${ARTIFACT_DIR}/e2e -c download-reports -oc exec -n ${CHE_NAMESPACE} ${HAPPY_PATH_POD_NAME} -c download-reports -- touch /tmp/done -EXIT_CODE=$(oc logs -n ${CHE_NAMESPACE} ${HAPPY_PATH_POD_NAME} -c happy-path-test | grep EXIT_CODE) -if [[ ${EXIT_CODE} != "+ EXIT_CODE=0" ]]; then - echo "[ERROR] Happy-path test failed. Check report at ${ARTIFACT_DIR}. Or happy path pod in eclipse-che namespace" - exit 1 -fi -echo "[INFO] Happy-path test succeed." +. "${SCRIPT_DIR}/provision-openshift-oauth-user.sh" +. "${SCRIPT_DIR}/start-happypath-tests.sh" END=$(date +%s.%N) echo "[INFO] Happy-path execution took $(echo "$END - $START" | bc) seconds." diff --git a/tests/devworkspace-happy-path/provision-openshift-oauth-user.sh b/tests/devworkspace-happy-path/provision-openshift-oauth-user.sh new file mode 100755 index 00000000000..508e7f33703 --- /dev/null +++ b/tests/devworkspace-happy-path/provision-openshift-oauth-user.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# +# Copyright (c) 2012-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 +# + +# exit immediately when a command fails +set -e +# only exit with zero if all commands of the pipeline exit successfully +set -o pipefail +# error on unset variables +set -u +# uncomment to print each command before executing it +# set -x + +SCRIPT_DIR=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +WORKDIR_KUBE="${WORKDIR:-${SCRIPT_DIR}/workdir/.kube}" + +rm -rf "${WORKDIR_KUBE}" && mkdir -p "${WORKDIR_KUBE}" + +# Create cluster-admin user inside of OpenShift cluster and login +function run() { + echo "[INFO] Testing if Che User exists." + KUBECONFIG="${KUBECONFIG:-${HOME}/.kube/config}" + TMP_KUBECONFIG="$WORKDIR_KUBE/kubeconfig" + cp "$KUBECONFIG" "$TMP_KUBECONFIG" + + if oc login -u che-user -p user --kubeconfig "${TMP_KUBECONFIG}"; then + echo "[INFO] Che User already exists. Using it" + return 0 + fi + echo "[INFO] Che User does not exist. Setting up htpasswd oauth for it." + oc delete secret dev-htpasswd-secret -n openshift-config || true + oc create secret generic dev-htpasswd-secret --from-file=htpasswd="$SCRIPT_DIR/resources/users.htpasswd" -n openshift-config + + if [[ $(oc get oauth cluster --ignore-not-found) == "" ]]; then + echo "[INFO] Creating a new OAuth Cluster since it's not found." + oc apply -f ${SCRIPT_DIR}/resources/cluster-oauth.yaml + # CustomResources don't support strategic merge. So, we need to merge or add array item depending on the object state + elif [[ $(oc get oauth/cluster -o=json | jq -e 'select (.spec.identityProviders == null)') ]]; then + # there are no identity providers. We can do merge and set the whole .spec.identityProviders field + echo "[INFO] No identity providers found, provisioning Che one." + oc patch oauth/cluster --type=merge -p "$(cat $SCRIPT_DIR/resources/cluster-oauth-patch.json)" + elif [[ ! $(oc get oauth/cluster -o=json | jq -e '.spec.identityProviders[]?.name? | select ( . == ("dev-htpasswd"))') ]]; then + # there are some identity providers. We should do add patch not to override existing identity providers + echo "[INFO] OAuth Cluster is found but dev-htpasswd provider missing. Provisioning it." + oc patch oauth/cluster --type=json -p '[{ + "op": "add", + "path": "/spec/identityProviders/0", + "value": { + "name":"dev-htpasswd", + "mappingMethod":"add", + "type":"HTPasswd", + "htpasswd": { + "fileData":{"name":"dev-htpasswd-secret"} + } + } + }]' + + else + echo "[INFO] dev-htpasswd oauth provider is found. Using it" + fi + + echo "[INFO] rollout oauth-openshift pods for applying OAuth configuration" + # apply just added identity providers, we need to rollout deployment for make sure + # that new IDP item will appear in the IDP table + # https://github.com/eclipse/che/issues/20822 + + oc rollout status -n openshift-authentication deployment/oauth-openshift + echo -e "[INFO] Waiting for htpasswd auth to be working up to 5 minutes" + CURRENT_TIME=$(date +%s) + ENDTIME=$(($CURRENT_TIME + 300)) + while [ $(date +%s) -lt $ENDTIME ]; do + if oc login -u happypath-dev -p dev --kubeconfig $TMP_KUBECONFIG; then + return 0 + fi + sleep 10 + done + echo "[ERROR] Che htpasswd changes are not affected after timeout." + exit 1 +} + +run diff --git a/tests/devworkspace-happy-path/start-happypath-tests.sh b/tests/devworkspace-happy-path/start-happypath-tests.sh new file mode 100755 index 00000000000..a1cb526bcf4 --- /dev/null +++ b/tests/devworkspace-happy-path/start-happypath-tests.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# +# Copyright (c) 2012-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 +# + +# exit immediately when a command fails +set -e +# only exit with zero if all commands of the pipeline exit successfully +set -o pipefail +# error on unset variables +set -u +# uncomment to print each command before executing it +# set -x + +SCRIPT_DIR=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) + +export WORKDIR="${WORKDIR:-${SCRIPT_DIR}/workdir/e2e}" +export CHE_NAMESPACE="${CHE_NAMESPACE:-eclipse-che}" +export E2E_TEST_IMAGE="${E2E_TEST_IMAGE:-quay.io/eclipse/che-e2e:next}" +export HAPPY_PATH_POD_NAME=happy-path-che +export HAPPY_PATH_TEST_PROJECT='https://github.com/che-samples/java-spring-petclinic/tree/devfilev2' +export HAPPY_PATH_SUITE="${HAPPY_PATH_SUITE:-test-all-devfiles}" +export HAPPY_PATH_USERSTORY="${HAPPY_PATH_USERSTORY:-EmptyWorkspace}" + +rm -rf "${WORKDIR}" && mkdir -p "${WORKDIR}" + +run() { + oc create namespace "${CHE_NAMESPACE}" || true + oc delete pod happy-path-che -n "${CHE_NAMESPACE}" --grace-period=30 --ignore-not-found + # patch happy-path-che.yaml + ECLIPSE_CHE_URL=${ECLIPSE_CHE_URL:-http://$(oc get route -n "${CHE_NAMESPACE}" che -o jsonpath='{.status.ingress[0].host}')} + TS_SELENIUM_DEVWORKSPACE_URL="${ECLIPSE_CHE_URL}/#${HAPPY_PATH_TEST_PROJECT}" + HAPPY_PATH_POD_FILE=${SCRIPT_DIR}/resources/pod-che-happy-path.yaml + cp $HAPPY_PATH_POD_FILE ${WORKDIR}/e2e-pod.yaml + sed -i "s@HAPPY_PATH_SUITE@${HAPPY_PATH_SUITE}@g" ${WORKDIR}/e2e-pod.yaml + sed -i "s@HAPPY_PATH_USERSTORY@${HAPPY_PATH_USERSTORY}@g" ${WORKDIR}/e2e-pod.yaml + sed -i "s@CHE_URL@${ECLIPSE_CHE_URL}@g" ${WORKDIR}/e2e-pod.yaml + sed -i "s@WORKSPACE_ROUTE@${TS_SELENIUM_DEVWORKSPACE_URL}@g" ${WORKDIR}/e2e-pod.yaml + sed -i "s@CHE-NAMESPACE@${CHE_NAMESPACE}@g" ${WORKDIR}/e2e-pod.yaml + sed -i "s|image: .*|image: ${E2E_TEST_IMAGE}|g" ${WORKDIR}/e2e-pod.yaml + echo "[INFO] Applying the following patched Che Happy Path Pod:" + cat ${WORKDIR}/e2e-pod.yaml + echo "[INFO] --------------------------------------------------" + oc apply -f ${WORKDIR}/e2e-pod.yaml + # wait for the pod to start + n=0 + while [ $n -le 120 ] + do + PHASE=$(oc get pod -n ${CHE_NAMESPACE} ${HAPPY_PATH_POD_NAME} \ + --template='{{ .status.phase }}') + if [[ ${PHASE} == "Running" ]]; then + echo "[INFO] Happy-path test started successfully." + return + fi + + sleep 5 + n=$(( n+1 )) + done + + echo "[ERROR] Failed to start happy-path test." + exit 1 +} + +run + +echo "[INFO] Waiting until happy path pod finished" +oc logs -n ${CHE_NAMESPACE} ${HAPPY_PATH_POD_NAME} -c happy-path-test -f +# just to sleep +sleep 3 + +echo "[INFO] Downloading test report." +mkdir "${ARTIFACT_DIR}/e2e" +oc rsync -n "${CHE_NAMESPACE}" ${HAPPY_PATH_POD_NAME}:/tmp/e2e/report/ "${ARTIFACT_DIR}/e2e" -c download-reports +oc exec -n "${CHE_NAMESPACE}" ${HAPPY_PATH_POD_NAME} -c download-reports -- touch /tmp/done + +EXIT_CODE=$(oc logs -n "${CHE_NAMESPACE}" ${HAPPY_PATH_POD_NAME} -c happy-path-test | grep EXIT_CODE) +if [[ ${EXIT_CODE} != "+ EXIT_CODE=0" ]]; then + echo "[ERROR] Happy-path test failed. Check report at ${ARTIFACT_DIR}. Or happy path pod in eclipse-che namespace" + exit 1 +fi +echo "[INFO] Happy-path test succeed." 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..2a376d589d2 --- /dev/null +++ b/tests/e2e/.eslintrc.js @@ -0,0 +1,197 @@ +/** ******************************************************************* + * 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', + { + default: [ + 'static-field', + 'public-field', + 'instance-field', + 'protected-field', + 'private-field', + 'abstract-field', + 'constructor', + 'public-static-method', + 'protected-static-method', + 'private-static-method', + 'public-method', + 'protected-method', + 'private-method' + ] + } + ], + '@typescript-eslint/explicit-function-return-type': [ + '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': 'off', + '@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/CODE_STYLE.md b/tests/e2e/CODE_STYLE.md new file mode 100644 index 00000000000..04d6f48f2d9 --- /dev/null +++ b/tests/e2e/CODE_STYLE.md @@ -0,0 +1,144 @@ +# Coding Standards and Conventions + +### Introducing + +#### Why are coding standards important? + +Coding standards offer several advantages, including: + +1. Increase Code Quality: By adhering to coding standards, developers can create code that is more secure, efficient, + maintainable, and uniform. This, in turn, can result in fewer errors and improved overall performance. + +2. Improved Readability and Maintainability: Coding standards contribute to code that is more comprehensible and easier + to maintain. Consistently formatted code aids other developers in comprehending and modifying it, saving time and + reducing the likelihood of introducing errors. + +3. Accelerated Development: The adherence to coding standards can expedite the development process. When developers + adhere to a predefined set of guidelines, they can produce code more swiftly and with fewer mistakes. Additionally, + uniform code formatting facilitates the identification and resolution of issues. + +4. Better Scalability: Coding standards facilitate the creation of scalable code, simplifying the incorporation of new + features or updates. Consistent coding practices also streamline code maintenance as the codebase expands. + +5. Elevated Collaboration and Communication: Uniform guidelines encourage better understanding and manipulation of code + written by fellow developers. This fosters smoother teamwork and facilitates the sharing of code. + +6. Consistency Across Projects: The adoption of coding standards guarantees a consistent coding approach across various + projects. This simplifies the task of upholding code quality, transitioning between tasks, and fostering + collaborative work. + +### Automated tools + +Automated lint checking and code format performs with ESLint and Prettier tools before every commit using Husky +pre-commit hook. +Full set of rules can be found: + +- [.eslintrc](.eslintrc.js) +- [.prettierrc](.prettierrc.json) + +### Preferable code style + +1. Page-object and util classes + + 1. ✔ Class declaration using dependency injection (inversify library) + + ``` + @injectable() + export class BrowserTabsUtil { + constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + ``` + + 2. Public methods + + - ✔ Declare public methods without "public "keyword + - ✔ Add Logger.debug() inside method to log its name (with optional message) + + ``` + async switchToWindow(windowHandle: string): Promise { + Logger.debug(); // logs BrowserUtils.sswitchToWindow + + await this.driverHelper.getDriver().switchTo().window(windowHandle); + } + ``` + + 3. Locators + + - ✔ For static locators - private static readonly fields type of By + + ``` + private static readonly FACTORY_URL_LOCATOR: By = By.xpath('//input[@id="git-repo-url"]'); + ``` + + - ✔ For dynamic locators - private methods which returns By + + ``` + private getExpandedActionsLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName)}//button[@aria-label='Actions' and @aria-expanded='true']`); + } + ``` + + - ✗ Avoid to declare locators as constant in methods + + ``` + async waitTitleContains(expectedText: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + const pageTitleLocator: By = By.xpath(`//h1[contains(text(), '${expectedText}')]`); + await this.driverHelper.waitVisibility(pageTitleLocator, timeout); + } + ``` + + #### Page object sample: + + ``` + import { e2eContainer } from '../../configs/inversify.config'; + + @injectable() + export class OcpMainPage { + + private static readonly MAIN_PAGE_HEADER_LOCATOR: By = By.id('page-main-header'); + private static readonly SELECT_ROLE_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="perspective-switcher-toggle"]'); + + constructor( + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + + async waitOpenMainPage(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(OcpMainPage.MAIN_PAGE_HEADER_LOCATOR, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + private getProjectDropdownItemLocator(projectName: string): By { + return By.xpath(`//button//*[text()="${projectName}"]`); + } + } + + ``` + +2. Mocha framework + + - ✔ TDD framework (`suite()`, `test()`) + - ✔ Inject class instances, declare all test data inside test `suit()` function to avoid unnecessary code execution if test suit will not be run + + ``` + suite('name', function(): void { + const webCheCodeLocators: Locators = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + // test specific data + const gitImportReference: string = 'pipeline'; + ``` + + - ✗ Don`t use arrow functions in test declaration https://mochajs.org/#arrow-functions + - ✔ Specs which don`t use browser should have API in name ending (like EmptyWorkspaceAPI.spec) + - ✗ Don\`t create scripts in package.json for each test. Instead of it use [dynamic config](configs/mocharc.ts), `mocha --spec` or `mocha --grep` flags to run specific test. + - ✔ Use test [./constants](constants) to make test flexible + +3. Packages + + 1. Add packages as dev dependencies + 2. If any changes re-create package-lock.json before push + +4. Comments + 1. If some code commented or added as workaround mark it as `//todo` with number of issue to get possibility to find it quickly + ``` + // todo commented due to issue crw-1010 + ``` diff --git a/tests/e2e/README.md b/tests/e2e/README.md index c2869d87cc5..754798e0639 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -1,87 +1,88 @@ - # 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. +- Local test results can be represented with Allure reporter `npm run open-allure-dasboard` + ## 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/README.md.orig b/tests/e2e/README.md.orig new file mode 100644 index 00000000000..eba933b0423 --- /dev/null +++ b/tests/e2e/README.md.orig @@ -0,0 +1,132 @@ +# Module for launch E2E tests related to Che 7 + +## Requirements + +<<<<<<< HEAD +- 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 +>>>>>>> main + +## Before launch + +**Perform commands:** + +- `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` + +## Custom launch + +<<<<<<< HEAD +- 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. +- Local test results can be represented with Allure reporter `npm run open-allure-dasboard` + +>>>>>>> main +## 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"` + +## 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"` + +## Debug docker launch + +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:** + +<<<<<<< HEAD +- 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`** +>>>>>>> main + +## Launching the DevWorkspaceHappyPath spec file using Che with oauth authentication + +**Setup next environment variables:** + +<<<<<<< HEAD +- 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) +>>>>>>> main + +**Execute the npm command:** + +- perform command `export USERSTORY=$TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME && npm run test-all-devfiles` diff --git a/tests/e2e/build/dockerfiles/Dockerfile b/tests/e2e/build/dockerfiles/Dockerfile index 83c2e7065aa..d7f19d44b0a 100644 --- a/tests/e2e/build/dockerfiles/Dockerfile +++ b/tests/e2e/build/dockerfiles/Dockerfile @@ -1,12 +1,12 @@ -FROM selenium/standalone-chrome:114.0 +FROM selenium/standalone-chrome:122.0 ENV DISPLAY=':20' USER root RUN apt-get update && apt-get install && \ - apt-get install -y ftp x11vnc ffmpeg libvpx6 && \ - curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - && \ + apt-get install -y ftp x11vnc ffmpeg libvpx7 && \ + curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - && \ apt-get install -y nodejs && \ npm install -g typescript && \ node -v diff --git a/tests/e2e/build/dockerfiles/Dockerfile.orig b/tests/e2e/build/dockerfiles/Dockerfile.orig new file mode 100644 index 00000000000..c575dea898c --- /dev/null +++ b/tests/e2e/build/dockerfiles/Dockerfile.orig @@ -0,0 +1,39 @@ +<<<<<<< HEAD +FROM selenium/standalone-chrome:114.0 +======= +FROM selenium/standalone-chrome:122.0 +>>>>>>> main + +ENV DISPLAY=':20' + +USER root + +RUN apt-get update && apt-get install && \ + apt-get install -y ftp x11vnc ffmpeg libvpx7 && \ + curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - && \ + apt-get install -y nodejs && \ + npm install -g typescript && \ + node -v + +COPY --chown=0:0 build/dockerfiles/entrypoint.sh /tmp/ + +RUN mkdir /tmp/e2e && \ + chmod -R 777 /tmp/e2e + +RUN sed -i "s/nodaemon=true/nodaemon=false/" /etc/supervisord.conf + +COPY package.json package-lock.json /tmp/e2e/ + +RUN cd /tmp/e2e && \ + npm i + +COPY . /tmp/e2e + +WORKDIR /tmp/e2e + +EXPOSE 5920 + +RUN chgrp -R 0 /tmp && \ + chmod -R g+rwX /tmp + +ENTRYPOINT [ "/tmp/entrypoint.sh" ] diff --git a/tests/e2e/configs/inversify.config.ts b/tests/e2e/configs/inversify.config.ts index ca7b660684f..4bb89cf6e52 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 @@ -12,7 +12,7 @@ import 'reflect-metadata'; import { Container } from 'inversify'; import { IDriver } from '../driver/IDriver'; import { ChromeDriver } from '../driver/ChromeDriver'; -import { TYPES, CLASSES } from './inversify.types'; +import { CLASSES, EXTERNAL_CLASSES, TYPES } from './inversify.types'; import { TestWorkspaceUtil } from '../utils/workspace/TestWorkspaceUtil'; import { IOcpLoginPage } from '../pageobjects/login/interfaces/IOcpLoginPage'; import { OcpUserLoginPage } from '../pageobjects/login/openshift/OcpUserLoginPage'; @@ -42,10 +42,20 @@ 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'; +import { CheCodeLocatorLoader } from '../pageobjects/ide/CheCodeLocatorLoader'; +import { LocatorLoader } from 'monaco-page-objects/out/locators/loader'; +import { OauthPage } from '../pageobjects/git-providers/OauthPage'; +import { DevfilesRegistryHelper } from '../utils/DevfilesRegistryHelper'; +import { Main as Generator } from '@eclipse-che/che-devworkspace-generator/lib/main'; +import { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../utils/KubernetesCommandLineToolsExecutor'; +import { ShellExecutor } from '../utils/ShellExecutor'; +import { UserPreferences } from '../pageobjects/dashboard/UserPreferences'; +import { WebTerminalPage } from '../pageobjects/webterminal/WebTerminalPage'; +import { TrustAuthorPopup } from '../pageobjects/dashboard/TrustAuthorPopup'; -const e2eContainer: Container = new Container({ defaultScope: 'Transient' }); +const e2eContainer: Container = new Container({ defaultScope: 'Transient', skipBaseClassChecks: true }); e2eContainer.bind(TYPES.Driver).to(ChromeDriver).inSingletonScope(); e2eContainer.bind(TYPES.WorkspaceUtil).to(TestWorkspaceUtil); @@ -59,11 +69,12 @@ e2eContainer.bind(CLASSES.WorkspaceDetails).to(WorkspaceDetail e2eContainer.bind(CLASSES.ScreenCatcher).to(ScreenCatcher); e2eContainer.bind(CLASSES.OcpLoginPage).to(OcpLoginPage); e2eContainer.bind(CLASSES.DexLoginPage).to(DexLoginPage); - +e2eContainer.bind(CLASSES.CheCodeLocatorLoader).to(CheCodeLocatorLoader); +e2eContainer.bind(CLASSES.LocatorLoader).to(LocatorLoader); +e2eContainer.bind(CLASSES.OauthPage).to(OauthPage); e2eContainer.bind(CLASSES.OcpMainPage).to(OcpMainPage); e2eContainer.bind(CLASSES.OcpImportFromGitPage).to(OcpImportFromGitPage); e2eContainer.bind(CLASSES.OcpApplicationPage).to(OcpApplicationPage); - e2eContainer.bind(CLASSES.CheApiRequestHandler).to(CheApiRequestHandler); e2eContainer.bind(CLASSES.CreateWorkspace).to(CreateWorkspace); e2eContainer.bind(CLASSES.ProjectAndFileTests).to(ProjectAndFileTests); @@ -72,11 +83,25 @@ e2eContainer.bind(CLASSES.StringUtil).to(StringUtil); e2eContainer.bind(CLASSES.ApiUrlResolver).to(ApiUrlResolver); e2eContainer.bind(CLASSES.WorkspaceHandlingTests).to(WorkspaceHandlingTests); e2eContainer.bind(CLASSES.RedHatLoginPage).to(RedHatLoginPage); +e2eContainer.bind(CLASSES.DevfilesRegistryHelper).to(DevfilesRegistryHelper); +e2eContainer.bind(CLASSES.KubernetesCommandLineToolsExecutor).to(KubernetesCommandLineToolsExecutor); +e2eContainer.bind(CLASSES.ShellExecutor).to(ShellExecutor); +e2eContainer.bind(CLASSES.ContainerTerminal).to(ContainerTerminal); +e2eContainer.bind(CLASSES.WebTerminalPage).to(WebTerminalPage); +e2eContainer.bind(CLASSES.UserPreferences).to(UserPreferences); +e2eContainer.bind(EXTERNAL_CLASSES.Generator).to(Generator); +e2eContainer.bind(EXTERNAL_CLASSES.LocatorLoader).to(LocatorLoader); +e2eContainer.bind(EXTERNAL_CLASSES.LocatorLoader).to(LocatorLoader); +e2eContainer.bind(CLASSES.TrustAuthorPopup).to(TrustAuthorPopup); -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.config.ts.orig b/tests/e2e/configs/inversify.config.ts.orig new file mode 100644 index 00000000000..a53a1393952 --- /dev/null +++ b/tests/e2e/configs/inversify.config.ts.orig @@ -0,0 +1,130 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import 'reflect-metadata'; +import { Container } from 'inversify'; +import { IDriver } from '../driver/IDriver'; +import { ChromeDriver } from '../driver/ChromeDriver'; +import { CLASSES, EXTERNAL_CLASSES, TYPES } from './inversify.types'; +import { TestWorkspaceUtil } from '../utils/workspace/TestWorkspaceUtil'; +import { IOcpLoginPage } from '../pageobjects/login/interfaces/IOcpLoginPage'; +import { OcpUserLoginPage } from '../pageobjects/login/openshift/OcpUserLoginPage'; +import { ICheLoginPage } from '../pageobjects/login/interfaces/ICheLoginPage'; +import { RegularUserOcpCheLoginPage } from '../pageobjects/login/openshift/RegularUserOcpCheLoginPage'; +import { DriverHelper } from '../utils/DriverHelper'; +import { Dashboard } from '../pageobjects/dashboard/Dashboard'; +import { Workspaces } from '../pageobjects/dashboard/Workspaces'; +import { WorkspaceDetails } from '../pageobjects/dashboard/workspace-details/WorkspaceDetails'; +import { ScreenCatcher } from '../utils/ScreenCatcher'; +import { OcpLoginPage } from '../pageobjects/login/openshift/OcpLoginPage'; +import { IAuthorizationHeaderHandler } from '../utils/request-handlers/headers/IAuthorizationHeaderHandler'; +import { CheMultiuserAuthorizationHeaderHandler } from '../utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler'; +import { CheApiRequestHandler } from '../utils/request-handlers/CheApiRequestHandler'; +import { CreateWorkspace } from '../pageobjects/dashboard/CreateWorkspace'; +import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; +import { WorkspaceHandlingTests } from '../tests-library/WorkspaceHandlingTests'; +import { ApiUrlResolver } from '../utils/workspace/ApiUrlResolver'; +import { ITestWorkspaceUtil } from '../utils/workspace/ITestWorkspaceUtil'; +import { ProjectAndFileTests } from '../tests-library/ProjectAndFileTests'; +import { LoginTests } from '../tests-library/LoginTests'; +import { RedHatLoginPage } from '../pageobjects/login/openshift/RedHatLoginPage'; +import { OcpRedHatLoginPage } from '../pageobjects/login/openshift/OcpRedHatLoginPage'; +import { OcpMainPage } from '../pageobjects/openshift/OcpMainPage'; +import { OcpImportFromGitPage } from '../pageobjects/openshift/OcpImportFromGitPage'; +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'; +<<<<<<< HEAD +import { OAuthConstants } from '../constants/OAuthConstants'; +import { BaseTestConstants, Platform } from '../constants/BaseTestConstants'; + +const e2eContainer: Container = new Container({ defaultScope: 'Transient' }); +======= +import { OAUTH_CONSTANTS } from '../constants/OAUTH_CONSTANTS'; +import { BASE_TEST_CONSTANTS, Platform } from '../constants/BASE_TEST_CONSTANTS'; +import { CheCodeLocatorLoader } from '../pageobjects/ide/CheCodeLocatorLoader'; +import { LocatorLoader } from 'monaco-page-objects/out/locators/loader'; +import { OauthPage } from '../pageobjects/git-providers/OauthPage'; +import { DevfilesRegistryHelper } from '../utils/DevfilesRegistryHelper'; +import { Main as Generator } from '@eclipse-che/che-devworkspace-generator/lib/main'; +import { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../utils/KubernetesCommandLineToolsExecutor'; +import { ShellExecutor } from '../utils/ShellExecutor'; +import { UserPreferences } from '../pageobjects/dashboard/UserPreferences'; +import { WebTerminalPage } from '../pageobjects/webterminal/WebTerminalPage'; +import { TrustAuthorPopup } from '../pageobjects/dashboard/TrustAuthorPopup'; + +const e2eContainer: Container = new Container({ defaultScope: 'Transient', skipBaseClassChecks: true }); +>>>>>>> main + +e2eContainer.bind(TYPES.Driver).to(ChromeDriver).inSingletonScope(); +e2eContainer.bind(TYPES.WorkspaceUtil).to(TestWorkspaceUtil); +e2eContainer.bind(TYPES.OcpLogin).to(OcpUserLoginPage); +e2eContainer.bind(TYPES.IAuthorizationHeaderHandler).to(CheMultiuserAuthorizationHeaderHandler); +e2eContainer.bind(CLASSES.BrowserTabsUtil).to(BrowserTabsUtil); +e2eContainer.bind(CLASSES.DriverHelper).to(DriverHelper); +e2eContainer.bind(CLASSES.Dashboard).to(Dashboard); +e2eContainer.bind(CLASSES.Workspaces).to(Workspaces); +e2eContainer.bind(CLASSES.WorkspaceDetails).to(WorkspaceDetails); +e2eContainer.bind(CLASSES.ScreenCatcher).to(ScreenCatcher); +e2eContainer.bind(CLASSES.OcpLoginPage).to(OcpLoginPage); +e2eContainer.bind(CLASSES.DexLoginPage).to(DexLoginPage); +<<<<<<< HEAD + +e2eContainer.bind(CLASSES.OcpMainPage).to(OcpMainPage); +e2eContainer.bind(CLASSES.OcpImportFromGitPage).to(OcpImportFromGitPage); +e2eContainer.bind(CLASSES.OcpApplicationPage).to(OcpApplicationPage); + +======= +e2eContainer.bind(CLASSES.CheCodeLocatorLoader).to(CheCodeLocatorLoader); +e2eContainer.bind(CLASSES.LocatorLoader).to(LocatorLoader); +e2eContainer.bind(CLASSES.OauthPage).to(OauthPage); +e2eContainer.bind(CLASSES.OcpMainPage).to(OcpMainPage); +e2eContainer.bind(CLASSES.OcpImportFromGitPage).to(OcpImportFromGitPage); +e2eContainer.bind(CLASSES.OcpApplicationPage).to(OcpApplicationPage); +>>>>>>> main +e2eContainer.bind(CLASSES.CheApiRequestHandler).to(CheApiRequestHandler); +e2eContainer.bind(CLASSES.CreateWorkspace).to(CreateWorkspace); +e2eContainer.bind(CLASSES.ProjectAndFileTests).to(ProjectAndFileTests); +e2eContainer.bind(CLASSES.LoginTests).to(LoginTests); +e2eContainer.bind(CLASSES.StringUtil).to(StringUtil); +e2eContainer.bind(CLASSES.ApiUrlResolver).to(ApiUrlResolver); +e2eContainer.bind(CLASSES.WorkspaceHandlingTests).to(WorkspaceHandlingTests); +e2eContainer.bind(CLASSES.RedHatLoginPage).to(RedHatLoginPage); +e2eContainer.bind(CLASSES.DevfilesRegistryHelper).to(DevfilesRegistryHelper); +e2eContainer.bind(CLASSES.KubernetesCommandLineToolsExecutor).to(KubernetesCommandLineToolsExecutor); +e2eContainer.bind(CLASSES.ShellExecutor).to(ShellExecutor); +e2eContainer.bind(CLASSES.ContainerTerminal).to(ContainerTerminal); +e2eContainer.bind(CLASSES.WebTerminalPage).to(WebTerminalPage); +e2eContainer.bind(CLASSES.UserPreferences).to(UserPreferences); +e2eContainer.bind(EXTERNAL_CLASSES.Generator).to(Generator); +e2eContainer.bind(EXTERNAL_CLASSES.LocatorLoader).to(LocatorLoader); +e2eContainer.bind(EXTERNAL_CLASSES.LocatorLoader).to(LocatorLoader); +e2eContainer.bind(CLASSES.TrustAuthorPopup).to(TrustAuthorPopup); + +<<<<<<< HEAD +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); +} +>>>>>>> main + +export { e2eContainer }; diff --git a/tests/e2e/configs/inversify.types.ts b/tests/e2e/configs/inversify.types.ts index a09d4d84057..ab89535896f 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,54 @@ **********************************************************************/ 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'), + IKubernetesCommandLineToolsExecutor: Symbol.for('IKubernetesCommandLineToolsExecutor'), + IContextParams: Symbol.for('IContextParams') }; 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', + CheCodeLocatorLoader: 'CheCodeLocatorLoader', + LocatorLoader: 'LocatorLoader', + OauthPage: 'OauthPage', + DevfilesRegistryHelper: 'DevfilesRegistryHelper', + KubernetesCommandLineToolsExecutor: 'KubernetesCommandLineToolsExecutor', + ShellExecutor: 'ShellExecutor', + ContainerTerminal: 'ContainerTerminal', + UserPreferences: 'UserPreferences', + WebTerminalPage: 'WebTerminalPage', + RevokeOauthPage: 'RevokeOauthPage', + TrustAuthorPopup: 'TrustAuthorPopup' }; -export { TYPES, CLASSES }; +const EXTERNAL_CLASSES: any = { + Generator: 'Generator', + LocatorLoader: 'LocatorLoader' +}; + +export { TYPES, CLASSES, EXTERNAL_CLASSES }; diff --git a/tests/e2e/configs/inversify.types.ts.orig b/tests/e2e/configs/inversify.types.ts.orig new file mode 100644 index 00000000000..e964c28c9db --- /dev/null +++ b/tests/e2e/configs/inversify.types.ts.orig @@ -0,0 +1,86 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +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'), + IKubernetesCommandLineToolsExecutor: Symbol.for('IKubernetesCommandLineToolsExecutor'), + IContextParams: Symbol.for('IContextParams') +}; + +const CLASSES: any = { +<<<<<<< HEAD + 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', + CheCodeLocatorLoader: 'CheCodeLocatorLoader', + LocatorLoader: 'LocatorLoader', + OauthPage: 'OauthPage', + DevfilesRegistryHelper: 'DevfilesRegistryHelper', + KubernetesCommandLineToolsExecutor: 'KubernetesCommandLineToolsExecutor', + ShellExecutor: 'ShellExecutor', + ContainerTerminal: 'ContainerTerminal', + UserPreferences: 'UserPreferences', + WebTerminalPage: 'WebTerminalPage', + RevokeOauthPage: 'RevokeOauthPage', + TrustAuthorPopup: 'TrustAuthorPopup' +>>>>>>> main +}; + +const EXTERNAL_CLASSES: any = { + Generator: 'Generator', + LocatorLoader: 'LocatorLoader' +}; + +export { TYPES, CLASSES, EXTERNAL_CLASSES }; diff --git a/tests/e2e/configs/mocharc.ts b/tests/e2e/configs/mocharc.ts index cbf6a79d584..7cc86c71074 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,36 @@ 'use strict'; -import { TimeoutConstants } from '../constants/TimeoutConstants'; +import { MOCHA_CONSTANTS } from '../constants/MOCHA_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; + +/** + * full available options list https://mochajs.org/api/mocha + */ 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: MOCHA_CONSTANTS.MOCHA_DEFAULT_TIMEOUT, + slow: 60000, + reporter: 'mocha-multi-reporters', + reporterOptions: 'configFile=configs/reporters.config.js', + ui: 'tdd', + extension: ['js', 'cjs', 'mjs'], + require: ['dist/specs/MochaHooks.js', 'ts-node/register'], + bail: MOCHA_CONSTANTS.MOCHA_BAIL, + 'full-trace': true, + spec: + BASE_TEST_CONSTANTS.TEST_ENVIRONMENT !== '' + ? `dist/suites/${MOCHA_CONSTANTS.MOCHA_DIRECTORY}/${MOCHA_CONSTANTS.MOCHA_SUITE}.suite.js` + : // 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. + MOCHA_CONSTANTS.MOCHA_DIRECTORY + ? // to run one file (name without extension). uses in "test", "test-all-devfiles". + MOCHA_CONSTANTS.MOCHA_USERSTORY + ? `dist/specs/${MOCHA_CONSTANTS.MOCHA_DIRECTORY}/${MOCHA_CONSTANTS.MOCHA_USERSTORY}.spec.js` + : `dist/specs/${MOCHA_CONSTANTS.MOCHA_DIRECTORY}/**.spec.js` + : MOCHA_CONSTANTS.MOCHA_USERSTORY + ? [`dist/specs/**/${MOCHA_CONSTANTS.MOCHA_USERSTORY}.spec.js`, `dist/specs/${MOCHA_CONSTANTS.MOCHA_USERSTORY}.spec.js`] + : ['dist/specs/**/**.spec.js', 'dist/specs/**.spec.js'], + retries: MOCHA_CONSTANTS.MOCHA_RETRIES, + grep: MOCHA_CONSTANTS.MOCHA_GREP }; diff --git a/tests/e2e/configs/mocharc.ts.orig b/tests/e2e/configs/mocharc.ts.orig new file mode 100644 index 00000000000..8bcc80d7d9f --- /dev/null +++ b/tests/e2e/configs/mocharc.ts.orig @@ -0,0 +1,77 @@ +<<<<<<< HEAD +/********************************************************************* + * Copyright (c) 2020-2023 Red Hat, Inc. +======= +/** ******************************************************************* + * copyright (c) 2020-2023 Red Hat, Inc. +>>>>>>> main + * + * 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 + **********************************************************************/ + +'use strict'; + +<<<<<<< HEAD +import { TimeoutConstants } from '../constants/TimeoutConstants'; + +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, +======= +import { MOCHA_CONSTANTS } from '../constants/MOCHA_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; + +/** + * full available options list https://mochajs.org/api/mocha + */ + +module.exports = { + timeout: MOCHA_CONSTANTS.MOCHA_DEFAULT_TIMEOUT, + slow: 60000, + reporter: 'mocha-multi-reporters', + reporterOptions: 'configFile=configs/reporters.config.js', + ui: 'tdd', + extension: ['js', 'cjs', 'mjs'], + require: ['dist/specs/MochaHooks.js', 'ts-node/register'], + bail: MOCHA_CONSTANTS.MOCHA_BAIL, + 'full-trace': true, + spec: + BASE_TEST_CONSTANTS.TEST_ENVIRONMENT !== '' + ? `dist/suites/${MOCHA_CONSTANTS.MOCHA_DIRECTORY}/${MOCHA_CONSTANTS.MOCHA_SUITE}.suite.js` + : // 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. + MOCHA_CONSTANTS.MOCHA_DIRECTORY + ? // to run one file (name without extension). uses in "test", "test-all-devfiles". + MOCHA_CONSTANTS.MOCHA_USERSTORY + ? `dist/specs/${MOCHA_CONSTANTS.MOCHA_DIRECTORY}/${MOCHA_CONSTANTS.MOCHA_USERSTORY}.spec.js` + : `dist/specs/${MOCHA_CONSTANTS.MOCHA_DIRECTORY}/**.spec.js` + : MOCHA_CONSTANTS.MOCHA_USERSTORY + ? [`dist/specs/**/${MOCHA_CONSTANTS.MOCHA_USERSTORY}.spec.js`, `dist/specs/${MOCHA_CONSTANTS.MOCHA_USERSTORY}.spec.js`] + : ['dist/specs/**/**.spec.js', 'dist/specs/**.spec.js'], + retries: MOCHA_CONSTANTS.MOCHA_RETRIES, + grep: MOCHA_CONSTANTS.MOCHA_GREP +>>>>>>> main +}; diff --git a/tests/e2e/configs/reporters.config.js b/tests/e2e/configs/reporters.config.js new file mode 100644 index 00000000000..29390f19d01 --- /dev/null +++ b/tests/e2e/configs/reporters.config.js @@ -0,0 +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 + **********************************************************************/ +const { REPORTER_CONSTANTS } = require('../constants/REPORTER_CONSTANTS'); +const { BASE_TEST_CONSTANTS } = require('../constants/BASE_TEST_CONSTANTS'); + +module.exports = { + reporterEnabled: REPORTER_CONSTANTS.REPORTERS_ENABLED(), + allureMochaReporterOptions: { + resultsDir: '.allure-results' + }, + reportportalAgentJsMochaReporterOptions: { + apiKey: REPORTER_CONSTANTS.RP_API_KEY, + endpoint: REPORTER_CONSTANTS.RP_ENDPOINT(), + project: REPORTER_CONSTANTS.RP_PROJECT(), + launch: `${REPORTER_CONSTANTS.RP_LAUNCH_NAME}`, + attributes: [ + { + key: 'build', + value: `${BASE_TEST_CONSTANTS.TESTING_APPLICATION_VERSION}` + }, + { + key: 'ocp version', + value: `${BASE_TEST_CONSTANTS.OCP_VERSION}` + }, + { + key: 'ocp infra', + value: `${BASE_TEST_CONSTANTS.OCP_INFRA}` + }, + { + key: 'application', + value: BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME() + }, + { + key: 'url', + value: BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL + }, + { + value: REPORTER_CONSTANTS.TEST_RUN_URL + } + ], + rerun: REPORTER_CONSTANTS.RP_RERUN(), + rerunOf: REPORTER_CONSTANTS.RP_RERUN_UUID, + restClientConfig: { + timeout: 1200000 + } + } +}; diff --git a/tests/e2e/configs/sh-scripts/runDevfileAcceptanceTests.sh b/tests/e2e/configs/sh-scripts/runDevfileAcceptanceTests.sh new file mode 100755 index 00000000000..572f5667696 --- /dev/null +++ b/tests/e2e/configs/sh-scripts/runDevfileAcceptanceTests.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# shellcheck source=/dev/null + +validateParameters(){ +# Validate required parameters + if [ -z "$TS_API_ACCEPTANCE_TEST_REGISTRY_URL" ] || [ -z "$TS_SELENIUM_BASE_URL" ]; then + echo "The TS_API_ACCEPTANCE_TEST_REGISTRY_URL or TS_SELENIUM_BASE_URL is not set!"; + echo "Please, set all required environment variable parameters" + exit 1 + fi +} + +######################################## +############# Methods ################## +######################################## + +launchDynamicallyGeneratingAPITests() { + export MOCHA_SUITE="DynamicallyGeneratingAPITest" + export RP_LAUNCH_NAME="Devfile Acceptance tests suite" + echo "MOCHA_SUITE = ${MOCHA_SUITE}" + echo "suites/$MOCHA_DIRECTORY/$MOCHA_SUITE" + npm run delayed-test +} + +initTestValues() { +export MOCHA_DIRECTORY="devfile-acceptance-test-suite" +if [[ "$TS_SELENIUM_BASE_URL" =~ "airgap" || (-n "$IS_CLUSTER_DISCONNECTED" && "$IS_CLUSTER_DISCONNECTED" == "true") ]] + then + echo "Disconnected environment" + else + echo "Online environment" + fi + + export TEST_ENVIRONMENT="$OCP_INFRA $MOCHA_DIRECTORY $OCP_VERSION" + export DELETE_WORKSPACE_ON_FAILED_TEST=${DELETE_WORKSPACE_ON_FAILED_TEST:-'false'} + export DELETE_SCREENCAST_IF_TEST_PASS=${DELETE_SCREENCAST_IF_TEST_PASS:-'true'} + export NODE_TLS_REJECT_UNAUTHORIZED=${NODE_TLS_REJECT_UNAUTHORIZED:-'0'} + export TS_OCP_LOGIN_PAGE_PROVIDER_TITLE=${TS_OCP_LOGIN_PAGE_PROVIDER_TITLE:-'htpasswd'} + export TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS=${TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS:-'1000'} + export TS_SELENIUM_EDITOR=${TS_SELENIUM_EDITOR:-'che-code'} + export TS_SELENIUM_EXECUTION_SCREENCAST=${TS_SELENIUM_EXECUTION_SCREENCAST:-'false'} + export TS_SELENIUM_HEADLESS=${TS_SELENIUM_HEADLESS:-'false'} + export TS_SELENIUM_LAUNCH_FULLSCREEN=${TS_SELENIUM_LAUNCH_FULLSCREEN:-'true'} + export TS_SELENIUM_LOG_LEVEL=${TS_SELENIUM_LOG_LEVEL:-'TRACE'} + export TS_SELENIUM_OCP_PASSWORD=${TS_SELENIUM_OCP_PASSWORD:-''} + export TS_SELENIUM_OCP_USERNAME=${TS_SELENIUM_OCP_USERNAME:-'admin'} + export TS_SELENIUM_VALUE_OPENSHIFT_OAUTH=${TS_SELENIUM_VALUE_OPENSHIFT_OAUTH:-'true'} + export TS_SELENIUM_REPORT_FOLDER=${TS_SELENIUM_REPORT_FOLDER:-'./report'} + export MOCHA_BAIL=${MOCHA_BAIL:-'false'} + export MOCHA_RETRIES=${MOCHA_RETRIES:-'1'} + + echo "TS_SELENIUM_BASE_URL=${TS_SELENIUM_BASE_URL}" + echo "TEST_ENVIRONMENT=${TEST_ENVIRONMENT}" + echo "DELETE_WORKSPACE_ON_FAILED_TEST=${DELETE_WORKSPACE_ON_FAILED_TEST}" + echo "DELETE_SCREENCAST_IF_TEST_PASS=${DELETE_SCREENCAST_IF_TEST_PASS}" + echo "NODE_TLS_REJECT_UNAUTHORIZED=${NODE_TLS_REJECT_UNAUTHORIZED}" + echo "TS_OCP_LOGIN_PAGE_PROVIDER_TITLE=${TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}" + echo "TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS=${TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS}" + echo "TS_SELENIUM_EDITOR=${TS_SELENIUM_EDITOR}" + echo "TS_SELENIUM_EXECUTION_SCREENCAST=${TS_SELENIUM_EXECUTION_SCREENCAST}" + echo "TS_SELENIUM_HEADLESS=${TS_SELENIUM_HEADLESS}" + echo "TS_SELENIUM_LAUNCH_FULLSCREEN=${TS_SELENIUM_LAUNCH_FULLSCREEN}" + echo "TS_SELENIUM_LOG_LEVEL=${TS_SELENIUM_LOG_LEVEL}" + echo "TS_SELENIUM_OCP_USERNAME=${TS_SELENIUM_OCP_USERNAME}" + echo "TS_SELENIUM_VALUE_OPENSHIFT_OAUTH=${TS_SELENIUM_VALUE_OPENSHIFT_OAUTH}" + echo "TS_SELENIUM_REPORT_FOLDER=${TS_SELENIUM_REPORT_FOLDER}" + echo "MOCHA_BAIL=${MOCHA_BAIL}" + echo "MOCHA_RETRIES=${MOCHA_RETRIES}" +} + +######################################## +############# Launching ################ +######################################## + +validateParameters + initTestValues + echo "" + echo "Launching devfile acceptance test suite for $TEST_ENVIRONMENT and registry $TS_API_ACCEPTANCE_TEST_REGISTRY_URL" + echo "" + launchDynamicallyGeneratingAPITests + diff --git a/tests/e2e/configs/sh-scripts/runFunctionalTests.sh b/tests/e2e/configs/sh-scripts/runFunctionalTests.sh new file mode 100755 index 00000000000..b46583410c5 --- /dev/null +++ b/tests/e2e/configs/sh-scripts/runFunctionalTests.sh @@ -0,0 +1,105 @@ +#!/bin/bash +# shellcheck source=/dev/null + +validateParameters(){ +# Validate required parameters + if [ -z "$OCP_VERSION" ] || [ -z "$OCP_INFRA" ] || [ -z "$TS_SELENIUM_BASE_URL" ]; then + echo "The OCP_INFRA, OCP_VERSION or TS_SELENIUM_BASE_URL is not set!"; + echo "Please, set all required environment variable parameters" + exit 1 + fi +} + +######################################## +############# Methods ################## +######################################## + +launchAPITests() { + export MOCHA_SUITE="APITest" + echo "MOCHA_SUITE = ${MOCHA_SUITE}" + export RP_LAUNCH_NAME="API tests suite $TEST_ENVIRONMENT" + echo "suites/$MOCHA_DIRECTORY/$MOCHA_SUITE" + npm run driver-less-test +} + +launchDynamicallyGeneratingAPITests() { + export MOCHA_SUITE="DynamicallyGeneratingAPITest" + export RP_LAUNCH_NAME="Application inbuilt DevWorkspaces API tests suite $TEST_ENVIRONMENT" + echo "MOCHA_SUITE = ${MOCHA_SUITE}" + echo "suites/$MOCHA_DIRECTORY/$MOCHA_SUITE" + npm run delayed-test +} + +launchUITests() { + export MOCHA_SUITE="UITest" + export RP_LAUNCH_NAME="UI tests suite $TEST_ENVIRONMENT" + echo "MOCHA_SUITE = ${MOCHA_SUITE}" + echo "suites/$MOCHA_DIRECTORY/$MOCHA_SUITE" + npm run test +} + +launchAllTests() { + validateParameters + initTestValues + echo "" + echo "Launching all tests for $TEST_ENVIRONMENT" + echo "" + launchDynamicallyGeneratingAPITests + launchAPITests + launchUITests +} + +initTestValues() { + if [[ "$TS_SELENIUM_BASE_URL" =~ "airgap" || (-n "$IS_CLUSTER_DISCONNECTED" && "$IS_CLUSTER_DISCONNECTED" == "true") ]] + then + echo "Disconnected environment" + export MOCHA_DIRECTORY="disconnected-ocp" + else + echo "Online environment" + export MOCHA_DIRECTORY="online-ocp" + fi + + export TEST_ENVIRONMENT="$OCP_INFRA $MOCHA_DIRECTORY $OCP_VERSION" + export DELETE_WORKSPACE_ON_FAILED_TEST=${DELETE_WORKSPACE_ON_FAILED_TEST:-'false'} + export DELETE_SCREENCAST_IF_TEST_PASS=${DELETE_SCREENCAST_IF_TEST_PASS:-'true'} + export NODE_TLS_REJECT_UNAUTHORIZED=${NODE_TLS_REJECT_UNAUTHORIZED:-'0'} + export TS_OCP_LOGIN_PAGE_PROVIDER_TITLE=${TS_OCP_LOGIN_PAGE_PROVIDER_TITLE:-'htpasswd'} + export TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS=${TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS:-'1000'} + export TS_SELENIUM_EDITOR=${TS_SELENIUM_EDITOR:-'che-code'} + export TS_SELENIUM_EXECUTION_SCREENCAST=${TS_SELENIUM_EXECUTION_SCREENCAST:-'false'} + export TS_SELENIUM_HEADLESS=${TS_SELENIUM_HEADLESS:-'false'} + export TS_SELENIUM_LAUNCH_FULLSCREEN=${TS_SELENIUM_LAUNCH_FULLSCREEN:-'true'} + export TS_SELENIUM_LOG_LEVEL=${TS_SELENIUM_LOG_LEVEL:-'TRACE'} + export TS_SELENIUM_OCP_PASSWORD=${TS_SELENIUM_OCP_PASSWORD:-''} + export TS_SELENIUM_OCP_USERNAME=${TS_SELENIUM_OCP_USERNAME:-'admin'} + export TS_SELENIUM_VALUE_OPENSHIFT_OAUTH=${TS_SELENIUM_VALUE_OPENSHIFT_OAUTH:-'true'} + export TS_SELENIUM_REPORT_FOLDER=${TS_SELENIUM_REPORT_FOLDER:-'./report'} + export MOCHA_BAIL=${MOCHA_BAIL:-'false'} + export MOCHA_RETRIES=${MOCHA_RETRIES:-'1'} + + + echo "TS_SELENIUM_BASE_URL=${TS_SELENIUM_BASE_URL}" + echo "TEST_ENVIRONMENT=${TEST_ENVIRONMENT}" + echo "DELETE_WORKSPACE_ON_FAILED_TEST=${DELETE_WORKSPACE_ON_FAILED_TEST}" + echo "DELETE_SCREENCAST_IF_TEST_PASS=${DELETE_SCREENCAST_IF_TEST_PASS}" + echo "NODE_TLS_REJECT_UNAUTHORIZED=${NODE_TLS_REJECT_UNAUTHORIZED}" + echo "TS_OCP_LOGIN_PAGE_PROVIDER_TITLE=${TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}" + echo "TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS=${TS_SELENIUM_DELAY_BETWEEN_SCREENSHOTS}" + echo "TS_SELENIUM_EDITOR=${TS_SELENIUM_EDITOR}" + echo "TS_SELENIUM_EXECUTION_SCREENCAST=${TS_SELENIUM_EXECUTION_SCREENCAST}" + echo "TS_SELENIUM_HEADLESS=${TS_SELENIUM_HEADLESS}" + echo "TS_SELENIUM_LAUNCH_FULLSCREEN=${TS_SELENIUM_LAUNCH_FULLSCREEN}" + echo "TS_SELENIUM_LOG_LEVEL=${TS_SELENIUM_LOG_LEVEL}" + echo "TS_SELENIUM_OCP_USERNAME=${TS_SELENIUM_OCP_USERNAME}" + echo "TS_SELENIUM_VALUE_OPENSHIFT_OAUTH=${TS_SELENIUM_VALUE_OPENSHIFT_OAUTH}" + echo "TS_SELENIUM_REPORT_FOLDER=${TS_SELENIUM_REPORT_FOLDER}" + echo "MOCHA_BAIL=${MOCHA_BAIL}" + echo "MOCHA_RETRIES=${MOCHA_RETRIES}" +} + +######################################## +############# Launching ################ +######################################## + +launchAllTests + diff --git a/tests/e2e/constants/API_TEST_CONSTANTS.ts b/tests/e2e/constants/API_TEST_CONSTANTS.ts new file mode 100644 index 00000000000..7e0cf53e727 --- /dev/null +++ b/tests/e2e/constants/API_TEST_CONSTANTS.ts @@ -0,0 +1,75 @@ +/** ******************************************************************* + * 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; + TS_GIT_API_AUTH_TOKEN: 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/', + /** + * gitHub has a rate limit for unauthorized requests to GitHub API. We can prevent this problems using authorization token + */ + TS_GIT_API_AUTH_TOKEN: process.env.TS_GIT_API_AUTH_TOKEN || '' +}; +export const API_TEST_CONSTANTS: { + TS_API_TEST_DEV_WORKSPACE_LIST: string | undefined; + 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 || ''; + }, + + TS_API_TEST_DEV_WORKSPACE_LIST: process.env.TS_API_TEST_DEV_WORKSPACE_LIST || undefined +}; diff --git a/tests/e2e/constants/BASE_TEST_CONSTANTS.ts b/tests/e2e/constants/BASE_TEST_CONSTANTS.ts new file mode 100644 index 00000000000..900ea1efe0d --- /dev/null +++ b/tests/e2e/constants/BASE_TEST_CONSTANTS.ts @@ -0,0 +1,137 @@ +/** ******************************************************************* + * 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: { + OCP_INFRA: string; + DELETE_WORKSPACE_ON_FAILED_TEST: boolean; + IS_CLUSTER_DISCONNECTED: () => boolean; + IS_PRODUCT_DOCUMENTATION_RELEASED: any; + OCP_VERSION: string; + TESTING_APPLICATION_VERSION: string; + TEST_ENVIRONMENT: string; + TS_DEBUG_MODE: boolean; + TS_LOAD_TESTS: string; + TS_PLATFORM: string; + TS_SELENIUM_BASE_URL: string; + TS_SELENIUM_DASHBOARD_SAMPLE_NAME: string; + TS_SELENIUM_EDITOR: string; + TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME: string; + TS_SELENIUM_PROJECT_ROOT_FILE_NAME: string; + TS_SELENIUM_REQUEST_INTERCEPTOR: boolean; + TS_SELENIUM_RESPONSE_INTERCEPTOR: boolean; + TESTING_APPLICATION_NAME: () => string; + TEST_NAMESPACE: string; +} = { + /** + * 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(/\/$/, ''), + + /** + * ocp infra type, possible values "PSI", "AWS", "IBM Z", "IBM Power" + */ + OCP_INFRA: process.env.OCP_INFRA || '', + + /** + * openShift version + */ + OCP_VERSION: process.env.OCP_VERSION || '', + + /** + * test environment (used as prefix in suite name) + */ + TEST_ENVIRONMENT: process.env.TEST_ENVIRONMENT || '', + + /** + * openshift project or k8s namespace which is used by test + */ + TEST_NAMESPACE: process.env.TEST_NAMESPACE || '', + + /** + * application name (DevSpaces or Che) + */ + TESTING_APPLICATION_NAME: (): string => { + return BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL.includes('devspaces') + ? 'devspaces' + : BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL.includes('che') + ? 'che' + : 'default'; + }, + /** + * testing application version + */ + TESTING_APPLICATION_VERSION: process.env.TESTING_APPLICATION_VERSION || 'next', + + /** + * is "https://access.redhat.com/documentation/en-us/red_hat_openshift_dev_spaces/{TESTING_APPLICATION_VERSION}/" available online + * false by default + */ + IS_PRODUCT_DOCUMENTATION_RELEASED: process.env.IS_PRODUCT_DOCUMENTATION_RELEASED === 'true', + + /** + * is cluster disconnected of online + */ + 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', + + /** + * sample name from Dashboard to start + */ + TS_SELENIUM_DASHBOARD_SAMPLE_NAME: process.env.TS_SELENIUM_DASHBOARD_SAMPLE_NAME || 'Python', + + /** + * 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..a6e67c65850 --- /dev/null +++ b/tests/e2e/constants/CHROME_DRIVER_CONSTANTS.ts @@ -0,0 +1,48 @@ +/** ******************************************************************* + * 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_W3C_CHROME_OPTION: boolean; + TS_SELENIUM_HEADLESS: boolean; + TS_USE_WEB_DRIVER_FOR_TEST: boolean; + TS_SELENIUM_LAUNCH_FULLSCREEN: boolean; + TS_SELENIUM_REMOTE_DRIVER_URL: string; + TS_SELENIUM_PROXY_SERVER: 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', + + /** + * run browser with proxy settings + */ + TS_SELENIUM_PROXY_SERVER: process.env.TS_SELENIUM_PROXY_SERVER || '' +}; diff --git a/tests/e2e/constants/FACTORY_TEST_CONSTANTS.ts b/tests/e2e/constants/FACTORY_TEST_CONSTANTS.ts new file mode 100644 index 00000000000..7671080ff0d --- /dev/null +++ b/tests/e2e/constants/FACTORY_TEST_CONSTANTS.ts @@ -0,0 +1,63 @@ +/** ******************************************************************* + * 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_SERVER_OAUTH1 = 'bitbucket-server-oauth1', + BITBUCKET_SERVER_OAUTH2 = 'bitbucket-server-oauth2', + BITBUCKET_CLOUD_OAUTH2 = 'bitbucket-org', + 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/MOCHA_CONSTANTS.ts b/tests/e2e/constants/MOCHA_CONSTANTS.ts new file mode 100644 index 00000000000..1fb05e96052 --- /dev/null +++ b/tests/e2e/constants/MOCHA_CONSTANTS.ts @@ -0,0 +1,37 @@ +/** ******************************************************************* + * 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 const MOCHA_CONSTANTS: { + MOCHA_SUITE: string | undefined; + MOCHA_DELAYED_SUITE: boolean; + MOCHA_DEFAULT_TIMEOUT: string | number; + MOCHA_DIRECTORY: string | undefined; + MOCHA_USERSTORY: undefined | string; + MOCHA_RETRIES: string | number; + MOCHA_BAIL: boolean; + MOCHA_GREP: string | undefined; +} = { + MOCHA_DIRECTORY: process.env.MOCHA_DIRECTORY || undefined, + + MOCHA_USERSTORY: process.env.USERSTORY || undefined, + + MOCHA_BAIL: process.env.MOCHA_BAIL !== 'false', + + MOCHA_DELAYED_SUITE: process.env.MOCHA_DELAYED_SUITE === 'true', + + MOCHA_DEFAULT_TIMEOUT: Number(process.env.MOCHA_DEFAULT_TIMEOUT) || 420000, + + MOCHA_RETRIES: process.env.MOCHA_RETRIES || BASE_TEST_CONSTANTS.TEST_ENVIRONMENT === '' ? 0 : 2, + + MOCHA_SUITE: process.env.MOCHA_SUITE || undefined, + + MOCHA_GREP: process.env.MOCHA_GREP || undefined +}; diff --git a/tests/e2e/constants/MONACO_CONSTANTS.ts b/tests/e2e/constants/MONACO_CONSTANTS.ts new file mode 100644 index 00000000000..581bcd4f620 --- /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.76.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/PLUGIN_TEST_CONSTANTS.ts b/tests/e2e/constants/PLUGIN_TEST_CONSTANTS.ts new file mode 100644 index 00000000000..2d524d6a518 --- /dev/null +++ b/tests/e2e/constants/PLUGIN_TEST_CONSTANTS.ts @@ -0,0 +1,16 @@ +/** ******************************************************************* + * 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,Java Lombok,Quarkus REST API,Python,.NET,C/C++,Go,PHP,Ansible' +}; diff --git a/tests/e2e/constants/REPORTER_CONSTANTS.ts b/tests/e2e/constants/REPORTER_CONSTANTS.ts new file mode 100644 index 00000000000..5d636bb82de --- /dev/null +++ b/tests/e2e/constants/REPORTER_CONSTANTS.ts @@ -0,0 +1,153 @@ +/** ******************************************************************* + * 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'; +import { MOCHA_CONSTANTS } from './MOCHA_CONSTANTS'; + +export const REPORTER_CONSTANTS: { + DELETE_SCREENCAST_IF_TEST_PASS: boolean; + RP_ENDPOINT(): string | undefined; + RP_IS_LOCAL_SERVER: boolean; + REPORTERS_ENABLED(): string; + RP_API_KEY: string; + RP_PROJECT(): string; + RP_RERUN(): boolean; + RP_RERUN_UUID: string | undefined; + RP_LAUNCH_NAME: string; + RP_USER: string; + RP_USE_PERSONAL: boolean; + SAVE_ALLURE_REPORT_DATA: boolean; + SAVE_RP_REPORT_DATA: boolean; + 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; + TEST_RUN_URL: string; +} = { + /** + * 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 || 'TRACE', + + /** + * print all timeout variables when tests launch, default to false + */ + TS_SELENIUM_PRINT_TIMEOUT_VARIABLES: process.env.TS_SELENIUM_PRINT_TIMEOUT_VARIABLES === 'true', + + /** + * use local Allure reporter, default to false + */ + SAVE_ALLURE_REPORT_DATA: process.env.SAVE_ALLURE_REPORT_DATA === 'true', + + /** + * use ReportPortal reporter, default to false + */ + SAVE_RP_REPORT_DATA: process.env.SAVE_RP_REPORT_DATA === 'true', + + /** + * list of enabler reporters + */ + REPORTERS_ENABLED: (): string => { + let reporters: string = 'dist/utils/CheReporter.js'; + if (REPORTER_CONSTANTS.SAVE_ALLURE_REPORT_DATA) { + reporters += ',allure-mocha'; + } + if (REPORTER_CONSTANTS.SAVE_RP_REPORT_DATA) { + reporters += ',@reportportal/agent-js-mocha'; + } + return reporters; + }, + + /** + * reportPortal app key or user token + */ + RP_API_KEY: process.env.RP_API_KEY || '', + + /** + * user name on ReportPortal + */ + RP_USER: process.env.RP_USER || process.env.USER || process.env.BUILD_USER_ID || '', + + /** + * launch name to save report + */ + RP_LAUNCH_NAME: process.env.RP_LAUNCH_NAME || `Test run ${MOCHA_CONSTANTS.MOCHA_USERSTORY}`, + + /** + * launch name to save report + */ + RP_RERUN_UUID: process.env.RP_RERUN_UUID || undefined, + + /** + * is launch rerun + */ + RP_RERUN: (): boolean => !!REPORTER_CONSTANTS.RP_RERUN_UUID, + + /** + * is local or online server to use + */ + RP_IS_LOCAL_SERVER: process.env.RP_IS_LOCAL_SERVER !== 'false', + + /** + * url with endpoints where ReportPortal is + */ + RP_ENDPOINT: (): string | undefined => { + if (process.env.RP_ENDPOINTRP_IS_LOCAL_SERVER) { + return 'http://localhost:8080/api/v1'; + } + if (process.env.RP_ENDPOINT !== '') { + return process.env.RP_ENDPOINT; + } + return 'https://reportportal-crw.apps.ocp-c1.prod.psi.redhat.com/api/v1'; + }, + + /** + * use personal project to save launch, if false launch will be sent to devspaces or che project, true by default + */ + RP_USE_PERSONAL: process.env.RP_USE_PERSONAL !== 'false', + + /** + * project name to save launch + */ + RP_PROJECT: (): string => { + const project: string = REPORTER_CONSTANTS.RP_USE_PERSONAL + ? `${REPORTER_CONSTANTS.RP_USER}_personal` + : BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME(); + return process.env.RP_PROJECT || project; + }, + + TEST_RUN_URL: process.env.TEST_RUN_URL || 'Test run url not set' +}; diff --git a/tests/e2e/constants/TIMEOUT_CONSTANTS.ts b/tests/e2e/constants/TIMEOUT_CONSTANTS.ts new file mode 100644 index 00000000000..93eb6f9b321 --- /dev/null +++ b/tests/e2e/constants/TIMEOUT_CONSTANTS.ts @@ -0,0 +1,125 @@ +/** ******************************************************************* + * 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_CLICK_DASHBOARD_ITEM_TIMEOUT: number; + TS_COMMON_DASHBOARD_WAIT_TIMEOUT: number; + TS_COMMON_PLUGIN_TEST_TIMEOUT: number; + TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT: number; + TS_DIALOG_WINDOW_DEFAULT_TIMEOUT: number; + TS_EDITOR_TAB_INTERACTION_TIMEOUT: number; + TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT: number; + TS_FIND_EXTENSION_TEST_TIMEOUT: number; + TS_IDE_LOAD_TIMEOUT: number; + TS_SELENIUM_CLICK_ON_VISIBLE_ITEM: number; + TS_SELENIUM_DEFAULT_ATTEMPTS: number; + TS_SELENIUM_DEFAULT_POLLING: number; + TS_SELENIUM_LOAD_PAGE_TIMEOUT: number; + TS_SELENIUM_START_WORKSPACE_TIMEOUT: number; + TS_SELENIUM_WAIT_FOR_URL: number; + TS_WAIT_LOADER_ABSENCE_TIMEOUT: number; + TS_WAIT_LOADER_PRESENCE_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, + + /** + * 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) || 60_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 interactions with editor tab - wait, click, select, "8 000" by default. + */ + TS_EDITOR_TAB_INTERACTION_TIMEOUT: Number(process.env.TS_OPEN_PROJECT_TREE_TIMEOUT) || 20_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, + + /** + * timeout for searching extension in marketplace. + */ + TS_FIND_EXTENSION_TEST_TIMEOUT: Number(process.env.TS_FIND_EXTENSION_TEST_TIMEOUT) || 15_000 +}; diff --git a/tests/e2e/constants/TimeoutConstants.ts.orig b/tests/e2e/constants/TimeoutConstants.ts.orig new file mode 100644 index 00000000000..3508e2688bf --- /dev/null +++ b/tests/e2e/constants/TimeoutConstants.ts.orig @@ -0,0 +1,113 @@ +/********************************************************************* + * 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 d81e88281e9..bdbd8725307 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 @@ -10,66 +10,60 @@ import 'chromedriver'; import 'reflect-metadata'; import { injectable } from 'inversify'; -import { ThenableWebDriver, Builder } from 'selenium-webdriver'; +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(); + options.setLoggingPrefs({ performance: 'ALL' }); + 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); - } + private getDriverOptions(): Options { + let options: Options = new Options() + .addArguments('--no-sandbox') + .addArguments('--disable-web-security') + .addArguments('--allow-running-insecure-content') + .addArguments('--ignore-certificate-errors'); - 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; - } + // if 'true' run in 'headless' mode + if (CHROME_DRIVER_CONSTANTS.TS_SELENIUM_HEADLESS) { + options = options.addArguments('headless'); + } - private getDriverBuilder(options: Options): Builder { - const disableW3copts: object = { 'goog:chromeOptions' : { 'w3c' : false }}; - let builder: Builder = new Builder() - .forBrowser('chrome') - .setChromeOptions(options); + if (CHROME_DRIVER_CONSTANTS.TS_SELENIUM_PROXY_SERVER !== '') { + options = options.addArguments('--proxy-server=' + CHROME_DRIVER_CONSTANTS.TS_SELENIUM_PROXY_SERVER); + } - // if 'false' w3c protocol is disabled - if (! ChromeDriverConstants.TS_SELENIUM_W3C_CHROME_OPTION) { - builder.withCapabilities(disableW3copts) - .forBrowser('chrome') - .setChromeOptions(options); - } + return options; + } - // if 'true' run with remote driver - if (ChromeDriverConstants.TS_SELENIUM_REMOTE_DRIVER_URL) { - builder = builder.usingServer(ChromeDriverConstants.TS_SELENIUM_REMOTE_DRIVER_URL); - } + private getDriverBuilder(options: Options): Builder { + const disableW3copts: object = { 'goog:chromeOptions': { w3c: false } }; + let builder: Builder = new Builder().forBrowser('chrome').setChromeOptions(options); - return builder; + // 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 (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/ChromeDriver.ts.orig b/tests/e2e/driver/ChromeDriver.ts.orig new file mode 100644 index 00000000000..991a6914dd8 --- /dev/null +++ b/tests/e2e/driver/ChromeDriver.ts.orig @@ -0,0 +1,118 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'chromedriver'; +import 'reflect-metadata'; +import { injectable } from 'inversify'; +import { Builder, ThenableWebDriver } from 'selenium-webdriver'; +import { IDriver } from './IDriver'; +import { Options } from 'selenium-webdriver/chrome'; +<<<<<<< HEAD +import { ChromeDriverConstants } from '../constants/ChromeDriverConstants'; +======= +import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; +>>>>>>> main + +@injectable() +export class ChromeDriver implements IDriver { + private readonly driver: ThenableWebDriver | undefined; + +<<<<<<< HEAD + 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(); + options.setLoggingPrefs({ performance: 'ALL' }); + if (CHROME_DRIVER_CONSTANTS.TS_USE_WEB_DRIVER_FOR_TEST) { + this.driver = this.getDriverBuilder(options).build(); + } + } +>>>>>>> main + + get(): ThenableWebDriver { + return this.driver as ThenableWebDriver; + } + +<<<<<<< HEAD + async setWindowSize(): Promise { + await (this.driver as ThenableWebDriver) + .manage() + .window() + .setSize(ChromeDriverConstants.TS_SELENIUM_RESOLUTION_WIDTH, ChromeDriverConstants.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'); + } +>>>>>>> main + + if (CHROME_DRIVER_CONSTANTS.TS_SELENIUM_PROXY_SERVER !== '') { + options = options.addArguments('--proxy-server=' + CHROME_DRIVER_CONSTANTS.TS_SELENIUM_PROXY_SERVER); + } + +<<<<<<< HEAD + // if 'false' w3c protocol is disabled + if (! ChromeDriverConstants.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 options; + } + + private getDriverBuilder(options: Options): Builder { + const disableW3copts: object = { 'goog:chromeOptions': { w3c: false } }; + let builder: Builder = new Builder().forBrowser('chrome').setChromeOptions(options); +>>>>>>> main + + // 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 (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 d2f8e7213a8..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..9f91e26cd3e 100644 --- a/tests/e2e/index.ts +++ b/tests/e2e/index.ts @@ -8,6 +8,8 @@ export * from './utils/BrowserTabsUtil'; export * from './utils/DevfilesRegistryHelper'; export * from './utils/DevWorkspaceConfigurationHelper'; export * from './utils/DriverHelper'; +export * from './utils/IContextParams'; +export * from './utils/IKubernetesCommandLineToolsExecutor'; export * from './utils/KubernetesCommandLineToolsExecutor'; export * from './utils/Logger'; export * from './utils/request-handlers/CheApiRequestHandler'; @@ -22,6 +24,8 @@ export * from './utils/workspace/TestWorkspaceUtil'; export * from './utils/workspace/WorkspaceStatus'; export * from './pageobjects/dashboard/CreateWorkspace'; export * from './pageobjects/dashboard/Dashboard'; +export * from './pageobjects/dashboard/TrustAuthorPopup'; +export * from './pageobjects/dashboard/UserPreferences'; export * from './pageobjects/dashboard/workspace-details/WorkspaceDetails'; export * from './pageobjects/dashboard/Workspaces'; export * from './pageobjects/git-providers/OauthPage'; @@ -38,15 +42,17 @@ export * from './pageobjects/login/openshift/RegularUserOcpCheLoginPage'; export * from './pageobjects/openshift/OcpApplicationPage'; export * from './pageobjects/openshift/OcpImportFromGitPage'; export * from './pageobjects/openshift/OcpMainPage'; +export * from './pageobjects/webterminal/WebTerminalPage'; 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/MOCHA_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/index.ts.orig b/tests/e2e/index.ts.orig new file mode 100644 index 00000000000..96195dd63fc --- /dev/null +++ b/tests/e2e/index.ts.orig @@ -0,0 +1,70 @@ +import * as inversifyConfig from './configs/inversify.config'; +export { inversifyConfig }; +export * from './configs/inversify.types'; +export * from './configs/mocharc'; +export * from './driver/ChromeDriver'; +export * from './driver/IDriver'; +export * from './utils/BrowserTabsUtil'; +export * from './utils/DevfilesRegistryHelper'; +export * from './utils/DevWorkspaceConfigurationHelper'; +export * from './utils/DriverHelper'; +export * from './utils/IContextParams'; +export * from './utils/IKubernetesCommandLineToolsExecutor'; +export * from './utils/KubernetesCommandLineToolsExecutor'; +export * from './utils/Logger'; +export * from './utils/request-handlers/CheApiRequestHandler'; +export * from './utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler'; +export * from './utils/request-handlers/headers/IAuthorizationHeaderHandler'; +export * from './utils/ScreenCatcher'; +export * from './utils/ShellExecutor'; +export * from './utils/StringUtil'; +export * from './utils/workspace/ApiUrlResolver'; +export * from './utils/workspace/ITestWorkspaceUtil'; +export * from './utils/workspace/TestWorkspaceUtil'; +export * from './utils/workspace/WorkspaceStatus'; +export * from './pageobjects/dashboard/CreateWorkspace'; +export * from './pageobjects/dashboard/Dashboard'; +export * from './pageobjects/dashboard/TrustAuthorPopup'; +export * from './pageobjects/dashboard/UserPreferences'; +export * from './pageobjects/dashboard/workspace-details/WorkspaceDetails'; +export * from './pageobjects/dashboard/Workspaces'; +export * from './pageobjects/git-providers/OauthPage'; +export * from './pageobjects/ide/CheCodeLocatorLoader'; +export * from './pageobjects/login/interfaces/ICheLoginPage'; +export * from './pageobjects/login/interfaces/IOcpLoginPage'; +export * from './pageobjects/login/kubernetes/DexLoginPage'; +export * from './pageobjects/login/kubernetes/KubernetesLoginPage'; +export * from './pageobjects/login/openshift/OcpLoginPage'; +export * from './pageobjects/login/openshift/OcpRedHatLoginPage'; +export * from './pageobjects/login/openshift/OcpUserLoginPage'; +export * from './pageobjects/login/openshift/RedHatLoginPage'; +export * from './pageobjects/login/openshift/RegularUserOcpCheLoginPage'; +export * from './pageobjects/openshift/OcpApplicationPage'; +export * from './pageobjects/openshift/OcpImportFromGitPage'; +export * from './pageobjects/openshift/OcpMainPage'; +export * from './pageobjects/webterminal/WebTerminalPage'; +export * from './tests-library/LoginTests'; +export * from './tests-library/ProjectAndFileTests'; +export * from './tests-library/WorkspaceHandlingTests'; +<<<<<<< HEAD +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/MOCHA_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'; +>>>>>>> main diff --git a/tests/e2e/package-lock.json b/tests/e2e/package-lock.json index b42281c34af..5e84767631d 100644 --- a/tests/e2e/package-lock.json +++ b/tests/e2e/package-lock.json @@ -1,3662 +1,5615 @@ { - "name": "@eclipse-che/che-e2e", - "version": "7.72.0-SNAPSHOT", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@eclipse-che/che-e2e", - "version": "7.72.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", - "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" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "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, - "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, - "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, - "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 - }, - "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, - "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, - "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 - }, - "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, - "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.67.0", - "resolved": "https://registry.npmjs.org/@eclipse-che/api/-/api-7.67.0.tgz", - "integrity": "sha512-y3xUABQ5fltnAJHbvME+hRjxrXjMYSWTmxYP6q3yIH95hOa8tka4D0jIEw4cNCnurkX5obk5hNJm0y2M5Zz40w==" - }, - "node_modules/@eclipse-che/che-devworkspace-generator": { - "version": "0.0.1-602dcb4", - "resolved": "https://registry.npmjs.org/@eclipse-che/che-devworkspace-generator/-/che-devworkspace-generator-0.0.1-602dcb4.tgz", - "integrity": "sha512-UW7xPR/cEpMCC25FoWzNzzxmu7m2WxSPmWE/l5lyCM0DbzXXQXA0H2q6X01QR+qDfWYscf6XNBSetOKXEkNE3g==", - "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/@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/@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/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/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.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", - "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/@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.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.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/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/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/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/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-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/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/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/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": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "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/chalk/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/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/chromedriver": { - "version": "114.0.2", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-114.0.2.tgz", - "integrity": "sha512-v0qrXRBknbxqmtklG7RWOe3TJ/dLaHhtB0jVxE7BAdYERxUjEaNRyqBwoGgVfQDibHCB0swzvzsj158nnfPgZw==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@testim/chrome-version": "^1.1.3", - "axios": "^1.4.0", - "compare-versions": "^5.0.3", - "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 - }, - "node_modules/compare-versions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", - "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==", - "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": "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/cross-spawn/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/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/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/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/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, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "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/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/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-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/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/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/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/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": "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/glob/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/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/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/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/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true - }, - "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-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", - "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-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-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/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-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/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/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/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/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/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/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/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/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.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=12.20" - } - }, - "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/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/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/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/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": "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/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/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/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/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/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.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "dependencies": { - "is-core-module": "^2.11.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/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/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": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "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": "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/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/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": "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/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/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": 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-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": "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/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/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/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": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "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, - "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, - "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, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "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, - "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, - "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 - }, - "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, - "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, - "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, - "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, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/tslint/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/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, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": 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/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-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "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/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/yaml": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", - "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", - "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" - } - } - } + "name": "@eclipse-che/che-e2e", + "version": "7.91.0-next", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@eclipse-che/che-e2e", + "version": "7.91.0-next", + "license": "ISC", + "dependencies": { + "@eclipse-che/api": "latest", + "inversify": "6.0.1", + "reflect-metadata": "0.1.13" + }, + "devDependencies": { + "@eclipse-che/che-devworkspace-generator": "next", + "@reportportal/agent-js-mocha": "^5.0.3", + "@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", + "allure-commandline": "^2.22.1", + "allure-decorators": "^2.4.0", + "allure-js-commons": "^2.4.0", + "allure-mocha": "^2.4.0", + "axios": "^0.25.0", + "chai": "^4.3.4", + "chrome-har": "^0.13.2", + "chromedriver": "^125.0.0", + "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", + "inversify-inject-decorators": "^3.1.0", + "mocha": "^9.1.3", + "mocha-allure-reporter": "^1.4.0", + "mocha-multi-reporters": "^1.5.1", + "monaco-page-objects": "3.9.1", + "prettier": "^3.0.2", + "rimraf": "2.6.2", + "selenium-webdriver": "4.6.1", + "shelljs": "^0.8.5", + "ts-node": "^10.9.1", + "typescript": "4.9.4", + "vscode-extension-tester-locators": "3.7.1", + "yaml": "^2.2.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@devfile/api": { + "version": "2.2.2-1700686170", + "resolved": "https://registry.npmjs.org/@devfile/api/-/api-2.2.2-1700686170.tgz", + "integrity": "sha512-mCIzvSce4Bu50HNybY0gWtSD1kujnXGvMVkzk0AAKMt1eSIAKtJeuTRPqQcLfrcfMRjF5t+AVOIIJ5LtlEfknA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "@types/node-fetch": "^2.5.7", + "es6-promise": "^4.2.4", + "form-data": "^2.5.0", + "node-fetch": "^2.6.0", + "url-parse": "^1.4.3" + } + }, + "node_modules/@eclipse-che/api": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@eclipse-che/api/-/api-7.86.0.tgz", + "integrity": "sha512-WDmnzopqKXPO3jozfrZ8mXVxdy/7KnzOv/+o3SzIqKYfEXXcmulG2+FYxzWUAA37T3wgqE1lQ+MACwO7v4PhtA==", + "license": "EPL-2.0" + }, + "node_modules/@eclipse-che/che-devworkspace-generator": { + "version": "7.87.0-next-f507c64", + "resolved": "https://registry.npmjs.org/@eclipse-che/che-devworkspace-generator/-/che-devworkspace-generator-7.87.0-next-f507c64.tgz", + "integrity": "sha512-Ue5tVn3kal2ORILq2T4AuO7DQhXlxbvYlb1F0e5c7itHL3YNw1y58/CaEebNErentgeRRjvjzqB48Wkxgol9UQ==", + "dev": true, + "license": "EPL-2.0", + "dependencies": { + "@devfile/api": "2.2.2-1700686170", + "axios": "1.6.0", + "fs-extra": "^10.0.0", + "inversify": "^5.0.1", + "js-yaml": "^4.0.0", + "jsonc-parser": "^3.0.0", + "jsonschema": "^1.4.1", + "reflect-metadata": "^0.1.13" + }, + "bin": { + "che-devworkspace-generator": "lib/entrypoint.js" + } + }, + "node_modules/@eclipse-che/che-devworkspace-generator/node_modules/axios": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", + "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/@eclipse-che/che-devworkspace-generator/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, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@eclipse-che/che-devworkspace-generator/node_modules/inversify": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.1.1.tgz", + "integrity": "sha512-j8grHGDzv1v+8T1sAQ+3boTCntFPfvxLCkNcxB1J8qA0lUN+fAlSyYd+RXKvaPRL4AGyPxViutBEJHNXOyUdFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "comment-parser": "1.4.1", + "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, + "license": "MIT", + "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.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "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/eslintrc/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@reportportal/agent-js-mocha": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@reportportal/agent-js-mocha/-/agent-js-mocha-5.0.4.tgz", + "integrity": "sha512-MPO5WeTMjBicu378Hp6tyq2OlNK9EL/WDHBvQodcfn1XX5fRlRSk1M6JqBsdn308O95UmECeqQ7VmRa9SpZdkw==", + "dev": true, + "license": "Apache 2.0", + "dependencies": { + "@reportportal/client-javascript": "~5.0.15", + "mocha": "^10.2.0" + }, + "engines": { + "node": ">=10.x" + } + }, + "node_modules/@reportportal/agent-js-mocha/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@reportportal/agent-js-mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@reportportal/agent-js-mocha/node_modules/mocha": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", + "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "8.1.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@reportportal/agent-js-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, + "license": "MIT" + }, + "node_modules/@reportportal/agent-js-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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@reportportal/agent-js-mocha/node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@reportportal/client-javascript": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/@reportportal/client-javascript/-/client-javascript-5.0.15.tgz", + "integrity": "sha512-ry6euqCOoJLXCUuBhlRMjCYKhbgU+9EYdZ8jpTuagoBVxS8V8nJed9ODnS4bXX61g+pJm+NP/0DrN2Ptq+DgQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "axios": "^0.27.2", + "axios-retry": "^3.4.0", + "glob": "^7.2.3", + "ini": "^2.0.0", + "uniqid": "^5.4.0", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=10.x" + } + }, + "node_modules/@reportportal/client-javascript/node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/@reportportal/client-javascript/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, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@testim/chrome-version": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz", + "integrity": "sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "4.3.16", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", + "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/clone-deep": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/clone-deep/-/clone-deep-4.0.4.tgz", + "integrity": "sha512-vXh6JuuaAha6sqEbJueYdh5zNBPPgG1OYumuz2UvLvriN6ABHDSW8ludREGWJb1MLIzbwZn4q4zUbUCerJTJfA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/node-fetch/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, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@types/ws": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/shelljs": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.15.tgz", + "integrity": "sha512-vzmnCHl6hViPu9GNLQJ+DZFd6BQI2DBTUeOvYHqkWQLMfKAAQYMb/xAmZkTogZI/vqXHCWkqDRymDI5p0QTi5Q==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin-tslint/-/eslint-plugin-tslint-6.21.0.tgz", + "integrity": "sha512-DktcL2dSnR90VCVHXYKUz40QQ5DY2lSvnbkQJ+b1BtWhj/sNXdtlmQR6vB6b4RyEm/GMhvLFj6Pq1MvVVXLMAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "6.21.0" + }, + "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/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "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/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "license": "MIT", + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.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/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "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, + "license": "ISC" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "MIT", + "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/allure-commandline": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/allure-commandline/-/allure-commandline-2.29.0.tgz", + "integrity": "sha512-he/oWJflViIdEmuQ4er5k+xRd//PaVVElHHTx01h6W71KM9qKiLeF5MloV93UBYoJRzjD9fgbZedSMKemCEGkQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "allure": "bin/allure" + } + }, + "node_modules/allure-decorators": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/allure-decorators/-/allure-decorators-2.15.1.tgz", + "integrity": "sha512-gG1jxEXWrMwx1+wwAix5XddzOCmW5BpGHchJtK6lB4GDsl84GtzK//gsWVTMQdhRT5kfAct4Wo1jn7r1A4NAVQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "allure-js-commons": "2.15.1" + } + }, + "node_modules/allure-js-commons": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-2.15.1.tgz", + "integrity": "sha512-5V/VINplbu0APnfSZOkYpKOzucO36Q2EtTD1kqjWjl7n6tj7Hh+IHCZsH3Vpk/LXRDfj9RuXugBBvwYKV5YMJw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "md5": "^2.3.0", + "properties": "^1.2.1", + "strip-ansi": "^5.2.0" + } + }, + "node_modules/allure-mocha": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/allure-mocha/-/allure-mocha-2.15.1.tgz", + "integrity": "sha512-4Hk2qUR6LdAUXNpPe73MV3DPKrBH7zy57lbAdb/D0poNIkdGEkzUYkpVPtW1imYfjqFXKBFEPOSJWqznGuiyjg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "allure-js-commons": "2.15.1" + }, + "peerDependencies": { + "mocha": ">=6.2.x" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "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, + "license": "ISC", + "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" + } + ], + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "Python-2.0" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=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, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.7" + } + }, + "node_modules/axios-retry": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.9.1.tgz", + "integrity": "sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.15.4", + "is-retry-allowed": "^2.2.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.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, + "license": "ISC" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "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, + "license": "MIT", + "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/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "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/" + } + ], + "license": "MIT", + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-har": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/chrome-har/-/chrome-har-0.13.2.tgz", + "integrity": "sha512-QiwyoilXiGVLG9Y0UMzWOyuao/PctTU9AAOTMqH7BuuulY1e0foDZ/O9qmLfdBAe6MbwIl9aDYvrlbyna3uRZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dayjs": "1.11.7", + "debug": "4.3.4", + "tough-cookie": "4.1.3", + "uuid": "9.0.0" + }, + "engines": { + "node": ">=14.19.1" + } + }, + "node_modules/chrome-har/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/chromedriver": { + "version": "125.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-125.0.0.tgz", + "integrity": "sha512-wWXrxWLWqXRTmRZDtPigs+ys44srlpHTpsL7MHnZc9iaE1oIB0hslSVeem6TcsEb1Ou8nvPx3vs5bPwCI6+VHg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@testim/chrome-version": "^1.1.4", + "axios": "^1.6.7", + "compare-versions": "^6.1.0", + "extract-zip": "^2.0.1", + "proxy-agent": "^6.4.0", + "proxy-from-env": "^1.1.0", + "tcp-port-used": "^1.0.2" + }, + "bin": { + "chromedriver": "bin/chromedriver" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chromedriver/node_modules/axios": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.1.tgz", + "integrity": "sha512-+LV37nQcd1EpFalkXksWNBiA17NZ5m5/WspmHGmZmdx1qBOg/VNq/c4eRJiA9VQQHBOs+N0ZhhdU10h2TyNK7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "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, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/clipboardy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", + "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arch": "^2.2.0", + "execa": "^5.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.4.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, + "license": "BSD-3-Clause", + "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, + "license": "MIT", + "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, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "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, + "license": "MIT", + "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, + "license": "MIT", + "peerDependencies": { + "eslint": ">=7.7.0" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz", + "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "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": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "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, + "license": "BSD-2-Clause", + "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, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-3-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "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/execa/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "BSD-2-Clause", + "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/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, + "license": "MIT" + }, + "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, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-type": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-7.7.1.tgz", + "integrity": "sha512-bTrKkzzZI6wH+NXhyD3SOXtb2zXTw2SbwI2RxUlRcXVsnN7jNL5hJzVQLYv7FOQhxFkK4XWdAflEaWFpaLLWpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "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, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC" + }, + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=4.x" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.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, + "license": "MIT", + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "ISC" + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/inversify": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz", + "integrity": "sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==", + "license": "MIT" + }, + "node_modules/inversify-inject-decorators": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/inversify-inject-decorators/-/inversify-inject-decorators-3.1.0.tgz", + "integrity": "sha512-/seBlVp5bXrLQS3DpKEmlgeZL6C7Tf/QITd+IMQrbBBGuCbxb7k3hRAWu9XSreNpFzLgSboz3sClLSEmGwHphw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha512-CSOkdn0/GhRFwxnipmhXfqJ+FG6+wkWBi46kKSsPx6+j65176ZiQcrCYpg6K8x3iLbO4k3zScBnZ7I/L80dAtw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "xmlcreate": "^1.0.1" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "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, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "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, + "license": "ISC" + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "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-allure-reporter": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/mocha-allure-reporter/-/mocha-allure-reporter-1.4.0.tgz", + "integrity": "sha512-Iqp4qxE9CBbikq3JjST9FY2JYFHtyoXb3i4u0g+h5KZBtjn4Rkb5ROfLeZLsnIf8RPK5nKcFGaH6DKrk7/fmYw==", + "deprecated": "This project has been renamed. Install using allure-mocha instead: https://www.npmjs.com/package/allure-mocha", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "allure-js-commons": "^1.3.2" + }, + "peerDependencies": { + "mocha": "*" + } + }, + "node_modules/mocha-allure-reporter/node_modules/allure-js-commons": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-1.3.2.tgz", + "integrity": "sha512-FTmoqP36ZjHFT4iLdYamyCFhyj1jqD6BIdiZ5pBlyafDJrFRV76XIXNxwRqbHpSw40o1vHzYi4vGpmREnhnHVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "file-type": "^7.7.1", + "fs-extra": "^6.0.1", + "js2xmlparser": "^3.0.0", + "mime": "^2.3.1", + "object-assign": "^4.1.1", + "uuid": "^3.0.0" + } + }, + "node_modules/mocha-allure-reporter/node_modules/fs-extra": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/mocha-allure-reporter/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/mocha-allure-reporter/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/mocha-allure-reporter/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, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/mocha-multi-reporters": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz", + "integrity": "sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "lodash": "^4.17.15" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "mocha": ">=3.1.2" + } + }, + "node_modules/mocha/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "license": "ISC", + "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/mocha/node_modules/glob/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "ISC", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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.9.1", + "resolved": "https://registry.npmjs.org/monaco-page-objects/-/monaco-page-objects-3.9.1.tgz", + "integrity": "sha512-Y/haEkl0U5MPH2krk6hyOpSqUdzqY9VIW4NPz48i6QHP1hSCInW2ffXl1zisStv0vBWBrDr8hu5n6Q1i7z99PQ==", + "deprecated": "Deprecated - This package was replaced by @redhat-developer/page-objects", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "clipboardy": "^3.0.0", + "clone-deep": "^4.0.1", + "compare-versions": "^6.1.0", + "fs-extra": "^11.1.1", + "ts-essentials": "^9.3.2" + }, + "peerDependencies": { + "selenium-webdriver": "^4.6.1", + "typescript": ">=4.6.2" + } + }, + "node_modules/monaco-page-objects/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "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, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": 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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "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, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "(MIT AND Zlib)" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC", + "peer": 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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/properties/-/properties-1.2.1.tgz", + "integrity": "sha512-qYNxyMj1JeW54i/EWEFsM1cVwxJbtgPp8+0Wg9XjNaK6VE/c4oRi6PNu5p7w1mNXEIQIjV5Wwn8v8Gz82/QzdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "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==", + "license": "Apache-2.0" + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.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, + "license": "ISC", + "dependencies": { + "glob": "^7.0.5" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "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" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "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, + "license": "MIT" + }, + "node_modules/selenium-webdriver": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.6.1.tgz", + "integrity": "sha512-FT8Dw0tbzaTp8YYLuwhaCnve/nw03HKrOJrA3aUmTKmxaIFSP4kT2R5fN3K0RpV5kbR0ZnM4FGVI2vANBvekaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jszip": "^3.10.0", + "tmp": "^0.2.1", + "ws": ">=8.7.0" + }, + "engines": { + "node": ">= 14.20.0" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "license": "ISC", + "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, + "license": "BSD-3-Clause", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "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, + "license": "ISC" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "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, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "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, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-essentials": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-9.4.2.tgz", + "integrity": "sha512-mB/cDhOvD7pg3YCLk2rOtejHjjdSi9in/IBYE13S+8WA5FBSraYf4V/ws55uvs0IvQ/l0wBOlXy5yBNZ9Bl8ZQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=4.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "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, + "license": "0BSD" + }, + "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, + "license": "Apache-2.0", + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/tslint/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, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/tslint/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, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/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, + "license": "BSD-3-Clause", + "peer": true + }, + "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, + "license": "MIT", + "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, + "license": "0BSD", + "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, + "license": "MIT", + "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, + "license": "0BSD", + "peer": 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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uniqid": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-5.4.0.tgz", + "integrity": "sha512-38JRbJ4Fj94VmnC7G/J/5n5SC7Ab46OM5iNtSstB/ko3l1b5g7ALt4qzHFgGciFkyiRNtDXtLNb+VsxtMSE77A==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "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, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.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, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/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, + "license": "MIT" + }, + "node_modules/vscode-extension-tester-locators": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/vscode-extension-tester-locators/-/vscode-extension-tester-locators-3.7.1.tgz", + "integrity": "sha512-My+ZTH2PM0g9JwWw49E+SfBMFLSjBdv6YpjekUFpzhCWK0mH+BjRC0gtINr+x2+KuVZVhsO82oSivBa1d7ZJvg==", + "deprecated": "Deprecated - This package was replaced by @redhat-developer/locators", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "monaco-page-objects": "^3.9.1", + "selenium-webdriver": "^4.6.1" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.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, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true, + "license": "Apache-2.0" + }, + "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, + "license": "MIT", + "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/wrap-ansi/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "dev": true, + "license": "MIT", + "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/xmlcreate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", + "integrity": "sha512-Mbe56Dvj00onbnSo9J0qj/XlY5bfN9KidsOnpd5tRCsR3ekB3hyyNU9fGrTdqNT5ZNvv4BsA2TcQlignsZyVcw==", + "dev": true, + "license": "Apache-2.0" + }, + "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, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "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, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } } diff --git a/tests/e2e/package-lock.json.orig b/tests/e2e/package-lock.json.orig new file mode 100644 index 00000000000..66818717580 --- /dev/null +++ b/tests/e2e/package-lock.json.orig @@ -0,0 +1,9278 @@ +{ +<<<<<<< HEAD + "name": "@eclipse-che/che-e2e", + "version": "7.72.0-SNAPSHOT", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@eclipse-che/che-e2e", + "version": "7.72.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", + "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" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "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, + "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, + "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, + "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 + }, + "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, + "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, + "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 + }, + "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, + "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.67.0", + "resolved": "https://registry.npmjs.org/@eclipse-che/api/-/api-7.67.0.tgz", + "integrity": "sha512-y3xUABQ5fltnAJHbvME+hRjxrXjMYSWTmxYP6q3yIH95hOa8tka4D0jIEw4cNCnurkX5obk5hNJm0y2M5Zz40w==" + }, + "node_modules/@eclipse-che/che-devworkspace-generator": { + "version": "0.0.1-602dcb4", + "resolved": "https://registry.npmjs.org/@eclipse-che/che-devworkspace-generator/-/che-devworkspace-generator-0.0.1-602dcb4.tgz", + "integrity": "sha512-UW7xPR/cEpMCC25FoWzNzzxmu7m2WxSPmWE/l5lyCM0DbzXXQXA0H2q6X01QR+qDfWYscf6XNBSetOKXEkNE3g==", + "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/@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/@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/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/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.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "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/@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.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.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/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/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/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/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-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/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/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/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": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "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/chalk/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/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/chromedriver": { + "version": "114.0.2", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-114.0.2.tgz", + "integrity": "sha512-v0qrXRBknbxqmtklG7RWOe3TJ/dLaHhtB0jVxE7BAdYERxUjEaNRyqBwoGgVfQDibHCB0swzvzsj158nnfPgZw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@testim/chrome-version": "^1.1.3", + "axios": "^1.4.0", + "compare-versions": "^5.0.3", + "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 + }, + "node_modules/compare-versions": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", + "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==", + "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": "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/cross-spawn/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/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/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/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/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, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "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/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/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-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/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/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/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/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": "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/glob/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/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/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/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/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, + "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-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "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-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-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/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-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/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/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/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/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/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/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/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/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.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "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/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/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/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/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": "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/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/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/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/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/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.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "dependencies": { + "is-core-module": "^2.11.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/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/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": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "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": "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/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/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": "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/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/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": 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-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": "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/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/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/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": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "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, + "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, + "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, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "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, + "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, + "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 + }, + "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, + "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, + "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, + "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, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/tslint/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/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, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": 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/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-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", + "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/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/yaml": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", + "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", + "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" + } + } + } +======= + "name": "@eclipse-che/che-e2e", + "version": "7.91.0-next", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@eclipse-che/che-e2e", + "version": "7.91.0-next", + "license": "ISC", + "dependencies": { + "@eclipse-che/api": "latest", + "inversify": "6.0.1", + "reflect-metadata": "0.1.13" + }, + "devDependencies": { + "@eclipse-che/che-devworkspace-generator": "next", + "@reportportal/agent-js-mocha": "^5.0.3", + "@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", + "allure-commandline": "^2.22.1", + "allure-decorators": "^2.4.0", + "allure-js-commons": "^2.4.0", + "allure-mocha": "^2.4.0", + "axios": "^0.25.0", + "chai": "^4.3.4", + "chrome-har": "^0.13.2", + "chromedriver": "^125.0.0", + "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", + "inversify-inject-decorators": "^3.1.0", + "mocha": "^9.1.3", + "mocha-allure-reporter": "^1.4.0", + "mocha-multi-reporters": "^1.5.1", + "monaco-page-objects": "3.9.1", + "prettier": "^3.0.2", + "rimraf": "2.6.2", + "selenium-webdriver": "4.6.1", + "shelljs": "^0.8.5", + "ts-node": "^10.9.1", + "typescript": "4.9.4", + "vscode-extension-tester-locators": "3.7.1", + "yaml": "^2.2.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@devfile/api": { + "version": "2.2.2-1700686170", + "resolved": "https://registry.npmjs.org/@devfile/api/-/api-2.2.2-1700686170.tgz", + "integrity": "sha512-mCIzvSce4Bu50HNybY0gWtSD1kujnXGvMVkzk0AAKMt1eSIAKtJeuTRPqQcLfrcfMRjF5t+AVOIIJ5LtlEfknA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "@types/node-fetch": "^2.5.7", + "es6-promise": "^4.2.4", + "form-data": "^2.5.0", + "node-fetch": "^2.6.0", + "url-parse": "^1.4.3" + } + }, + "node_modules/@eclipse-che/api": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@eclipse-che/api/-/api-7.86.0.tgz", + "integrity": "sha512-WDmnzopqKXPO3jozfrZ8mXVxdy/7KnzOv/+o3SzIqKYfEXXcmulG2+FYxzWUAA37T3wgqE1lQ+MACwO7v4PhtA==", + "license": "EPL-2.0" + }, + "node_modules/@eclipse-che/che-devworkspace-generator": { + "version": "7.87.0-next-f507c64", + "resolved": "https://registry.npmjs.org/@eclipse-che/che-devworkspace-generator/-/che-devworkspace-generator-7.87.0-next-f507c64.tgz", + "integrity": "sha512-Ue5tVn3kal2ORILq2T4AuO7DQhXlxbvYlb1F0e5c7itHL3YNw1y58/CaEebNErentgeRRjvjzqB48Wkxgol9UQ==", + "dev": true, + "license": "EPL-2.0", + "dependencies": { + "@devfile/api": "2.2.2-1700686170", + "axios": "1.6.0", + "fs-extra": "^10.0.0", + "inversify": "^5.0.1", + "js-yaml": "^4.0.0", + "jsonc-parser": "^3.0.0", + "jsonschema": "^1.4.1", + "reflect-metadata": "^0.1.13" + }, + "bin": { + "che-devworkspace-generator": "lib/entrypoint.js" + } + }, + "node_modules/@eclipse-che/che-devworkspace-generator/node_modules/axios": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", + "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/@eclipse-che/che-devworkspace-generator/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, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@eclipse-che/che-devworkspace-generator/node_modules/inversify": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.1.1.tgz", + "integrity": "sha512-j8grHGDzv1v+8T1sAQ+3boTCntFPfvxLCkNcxB1J8qA0lUN+fAlSyYd+RXKvaPRL4AGyPxViutBEJHNXOyUdFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "comment-parser": "1.4.1", + "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, + "license": "MIT", + "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.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "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/eslintrc/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@reportportal/agent-js-mocha": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@reportportal/agent-js-mocha/-/agent-js-mocha-5.0.4.tgz", + "integrity": "sha512-MPO5WeTMjBicu378Hp6tyq2OlNK9EL/WDHBvQodcfn1XX5fRlRSk1M6JqBsdn308O95UmECeqQ7VmRa9SpZdkw==", + "dev": true, + "license": "Apache 2.0", + "dependencies": { + "@reportportal/client-javascript": "~5.0.15", + "mocha": "^10.2.0" + }, + "engines": { + "node": ">=10.x" + } + }, + "node_modules/@reportportal/agent-js-mocha/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@reportportal/agent-js-mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@reportportal/agent-js-mocha/node_modules/mocha": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", + "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "8.1.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@reportportal/agent-js-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, + "license": "MIT" + }, + "node_modules/@reportportal/agent-js-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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@reportportal/agent-js-mocha/node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@reportportal/client-javascript": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/@reportportal/client-javascript/-/client-javascript-5.0.15.tgz", + "integrity": "sha512-ry6euqCOoJLXCUuBhlRMjCYKhbgU+9EYdZ8jpTuagoBVxS8V8nJed9ODnS4bXX61g+pJm+NP/0DrN2Ptq+DgQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "axios": "^0.27.2", + "axios-retry": "^3.4.0", + "glob": "^7.2.3", + "ini": "^2.0.0", + "uniqid": "^5.4.0", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=10.x" + } + }, + "node_modules/@reportportal/client-javascript/node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/@reportportal/client-javascript/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, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@testim/chrome-version": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz", + "integrity": "sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "4.3.16", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", + "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/clone-deep": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/clone-deep/-/clone-deep-4.0.4.tgz", + "integrity": "sha512-vXh6JuuaAha6sqEbJueYdh5zNBPPgG1OYumuz2UvLvriN6ABHDSW8ludREGWJb1MLIzbwZn4q4zUbUCerJTJfA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/node-fetch/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, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@types/ws": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/shelljs": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.15.tgz", + "integrity": "sha512-vzmnCHl6hViPu9GNLQJ+DZFd6BQI2DBTUeOvYHqkWQLMfKAAQYMb/xAmZkTogZI/vqXHCWkqDRymDI5p0QTi5Q==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin-tslint/-/eslint-plugin-tslint-6.21.0.tgz", + "integrity": "sha512-DktcL2dSnR90VCVHXYKUz40QQ5DY2lSvnbkQJ+b1BtWhj/sNXdtlmQR6vB6b4RyEm/GMhvLFj6Pq1MvVVXLMAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "6.21.0" + }, + "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/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "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/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "license": "MIT", + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.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/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "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.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "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, + "license": "ISC" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "MIT", + "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/allure-commandline": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/allure-commandline/-/allure-commandline-2.29.0.tgz", + "integrity": "sha512-he/oWJflViIdEmuQ4er5k+xRd//PaVVElHHTx01h6W71KM9qKiLeF5MloV93UBYoJRzjD9fgbZedSMKemCEGkQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "allure": "bin/allure" + } + }, + "node_modules/allure-decorators": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/allure-decorators/-/allure-decorators-2.15.1.tgz", + "integrity": "sha512-gG1jxEXWrMwx1+wwAix5XddzOCmW5BpGHchJtK6lB4GDsl84GtzK//gsWVTMQdhRT5kfAct4Wo1jn7r1A4NAVQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "allure-js-commons": "2.15.1" + } + }, + "node_modules/allure-js-commons": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-2.15.1.tgz", + "integrity": "sha512-5V/VINplbu0APnfSZOkYpKOzucO36Q2EtTD1kqjWjl7n6tj7Hh+IHCZsH3Vpk/LXRDfj9RuXugBBvwYKV5YMJw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "md5": "^2.3.0", + "properties": "^1.2.1", + "strip-ansi": "^5.2.0" + } + }, + "node_modules/allure-mocha": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/allure-mocha/-/allure-mocha-2.15.1.tgz", + "integrity": "sha512-4Hk2qUR6LdAUXNpPe73MV3DPKrBH7zy57lbAdb/D0poNIkdGEkzUYkpVPtW1imYfjqFXKBFEPOSJWqznGuiyjg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "allure-js-commons": "2.15.1" + }, + "peerDependencies": { + "mocha": ">=6.2.x" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "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, + "license": "ISC", + "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" + } + ], + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "Python-2.0" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=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, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.7" + } + }, + "node_modules/axios-retry": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.9.1.tgz", + "integrity": "sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.15.4", + "is-retry-allowed": "^2.2.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.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, + "license": "ISC" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "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, + "license": "MIT", + "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/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "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/" + } + ], + "license": "MIT", + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-har": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/chrome-har/-/chrome-har-0.13.2.tgz", + "integrity": "sha512-QiwyoilXiGVLG9Y0UMzWOyuao/PctTU9AAOTMqH7BuuulY1e0foDZ/O9qmLfdBAe6MbwIl9aDYvrlbyna3uRZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dayjs": "1.11.7", + "debug": "4.3.4", + "tough-cookie": "4.1.3", + "uuid": "9.0.0" + }, + "engines": { + "node": ">=14.19.1" + } + }, + "node_modules/chrome-har/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/chromedriver": { + "version": "125.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-125.0.0.tgz", + "integrity": "sha512-wWXrxWLWqXRTmRZDtPigs+ys44srlpHTpsL7MHnZc9iaE1oIB0hslSVeem6TcsEb1Ou8nvPx3vs5bPwCI6+VHg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@testim/chrome-version": "^1.1.4", + "axios": "^1.6.7", + "compare-versions": "^6.1.0", + "extract-zip": "^2.0.1", + "proxy-agent": "^6.4.0", + "proxy-from-env": "^1.1.0", + "tcp-port-used": "^1.0.2" + }, + "bin": { + "chromedriver": "bin/chromedriver" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chromedriver/node_modules/axios": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.1.tgz", + "integrity": "sha512-+LV37nQcd1EpFalkXksWNBiA17NZ5m5/WspmHGmZmdx1qBOg/VNq/c4eRJiA9VQQHBOs+N0ZhhdU10h2TyNK7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "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, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/clipboardy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", + "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arch": "^2.2.0", + "execa": "^5.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.4.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, + "license": "BSD-3-Clause", + "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, + "license": "MIT", + "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, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "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, + "license": "MIT", + "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, + "license": "MIT", + "peerDependencies": { + "eslint": ">=7.7.0" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz", + "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "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": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "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, + "license": "BSD-2-Clause", + "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, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-3-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "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/execa/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "BSD-2-Clause", + "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/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, + "license": "MIT" + }, + "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, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-type": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-7.7.1.tgz", + "integrity": "sha512-bTrKkzzZI6wH+NXhyD3SOXtb2zXTw2SbwI2RxUlRcXVsnN7jNL5hJzVQLYv7FOQhxFkK4XWdAflEaWFpaLLWpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "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, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC" + }, + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=4.x" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.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, + "license": "MIT", + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "ISC" + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/inversify": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz", + "integrity": "sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==", + "license": "MIT" + }, + "node_modules/inversify-inject-decorators": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/inversify-inject-decorators/-/inversify-inject-decorators-3.1.0.tgz", + "integrity": "sha512-/seBlVp5bXrLQS3DpKEmlgeZL6C7Tf/QITd+IMQrbBBGuCbxb7k3hRAWu9XSreNpFzLgSboz3sClLSEmGwHphw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha512-CSOkdn0/GhRFwxnipmhXfqJ+FG6+wkWBi46kKSsPx6+j65176ZiQcrCYpg6K8x3iLbO4k3zScBnZ7I/L80dAtw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "xmlcreate": "^1.0.1" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "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, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "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, + "license": "ISC" + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "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-allure-reporter": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/mocha-allure-reporter/-/mocha-allure-reporter-1.4.0.tgz", + "integrity": "sha512-Iqp4qxE9CBbikq3JjST9FY2JYFHtyoXb3i4u0g+h5KZBtjn4Rkb5ROfLeZLsnIf8RPK5nKcFGaH6DKrk7/fmYw==", + "deprecated": "This project has been renamed. Install using allure-mocha instead: https://www.npmjs.com/package/allure-mocha", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "allure-js-commons": "^1.3.2" + }, + "peerDependencies": { + "mocha": "*" + } + }, + "node_modules/mocha-allure-reporter/node_modules/allure-js-commons": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-1.3.2.tgz", + "integrity": "sha512-FTmoqP36ZjHFT4iLdYamyCFhyj1jqD6BIdiZ5pBlyafDJrFRV76XIXNxwRqbHpSw40o1vHzYi4vGpmREnhnHVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "file-type": "^7.7.1", + "fs-extra": "^6.0.1", + "js2xmlparser": "^3.0.0", + "mime": "^2.3.1", + "object-assign": "^4.1.1", + "uuid": "^3.0.0" + } + }, + "node_modules/mocha-allure-reporter/node_modules/fs-extra": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/mocha-allure-reporter/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/mocha-allure-reporter/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/mocha-allure-reporter/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, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/mocha-multi-reporters": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz", + "integrity": "sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "lodash": "^4.17.15" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "mocha": ">=3.1.2" + } + }, + "node_modules/mocha/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "license": "ISC", + "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/mocha/node_modules/glob/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "ISC", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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.9.1", + "resolved": "https://registry.npmjs.org/monaco-page-objects/-/monaco-page-objects-3.9.1.tgz", + "integrity": "sha512-Y/haEkl0U5MPH2krk6hyOpSqUdzqY9VIW4NPz48i6QHP1hSCInW2ffXl1zisStv0vBWBrDr8hu5n6Q1i7z99PQ==", + "deprecated": "Deprecated - This package was replaced by @redhat-developer/page-objects", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "clipboardy": "^3.0.0", + "clone-deep": "^4.0.1", + "compare-versions": "^6.1.0", + "fs-extra": "^11.1.1", + "ts-essentials": "^9.3.2" + }, + "peerDependencies": { + "selenium-webdriver": "^4.6.1", + "typescript": ">=4.6.2" + } + }, + "node_modules/monaco-page-objects/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "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, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": 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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "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, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "(MIT AND Zlib)" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC", + "peer": 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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/properties/-/properties-1.2.1.tgz", + "integrity": "sha512-qYNxyMj1JeW54i/EWEFsM1cVwxJbtgPp8+0Wg9XjNaK6VE/c4oRi6PNu5p7w1mNXEIQIjV5Wwn8v8Gz82/QzdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "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==", + "license": "Apache-2.0" + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.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, + "license": "ISC", + "dependencies": { + "glob": "^7.0.5" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "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" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "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, + "license": "MIT" + }, + "node_modules/selenium-webdriver": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.6.1.tgz", + "integrity": "sha512-FT8Dw0tbzaTp8YYLuwhaCnve/nw03HKrOJrA3aUmTKmxaIFSP4kT2R5fN3K0RpV5kbR0ZnM4FGVI2vANBvekaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jszip": "^3.10.0", + "tmp": "^0.2.1", + "ws": ">=8.7.0" + }, + "engines": { + "node": ">= 14.20.0" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "license": "ISC", + "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, + "license": "BSD-3-Clause", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "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, + "license": "ISC" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "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, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "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, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-essentials": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-9.4.2.tgz", + "integrity": "sha512-mB/cDhOvD7pg3YCLk2rOtejHjjdSi9in/IBYE13S+8WA5FBSraYf4V/ws55uvs0IvQ/l0wBOlXy5yBNZ9Bl8ZQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=4.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "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, + "license": "0BSD" + }, + "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, + "license": "Apache-2.0", + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/tslint/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, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-3-Clause", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/tslint/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, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/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, + "license": "BSD-3-Clause", + "peer": true + }, + "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, + "license": "MIT", + "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, + "license": "0BSD", + "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, + "license": "MIT", + "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, + "license": "0BSD", + "peer": 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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uniqid": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-5.4.0.tgz", + "integrity": "sha512-38JRbJ4Fj94VmnC7G/J/5n5SC7Ab46OM5iNtSstB/ko3l1b5g7ALt4qzHFgGciFkyiRNtDXtLNb+VsxtMSE77A==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "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, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.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, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/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, + "license": "MIT" + }, + "node_modules/vscode-extension-tester-locators": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/vscode-extension-tester-locators/-/vscode-extension-tester-locators-3.7.1.tgz", + "integrity": "sha512-My+ZTH2PM0g9JwWw49E+SfBMFLSjBdv6YpjekUFpzhCWK0mH+BjRC0gtINr+x2+KuVZVhsO82oSivBa1d7ZJvg==", + "deprecated": "Deprecated - This package was replaced by @redhat-developer/locators", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "monaco-page-objects": "^3.9.1", + "selenium-webdriver": "^4.6.1" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.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, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true, + "license": "Apache-2.0" + }, + "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, + "license": "MIT", + "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/wrap-ansi/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "dev": true, + "license": "MIT", + "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/xmlcreate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", + "integrity": "sha512-Mbe56Dvj00onbnSo9J0qj/XlY5bfN9KidsOnpd5tRCsR3ekB3hyyNU9fGrTdqNT5ZNvv4BsA2TcQlignsZyVcw==", + "dev": true, + "license": "Apache-2.0" + }, + "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, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "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, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +>>>>>>> main +} diff --git a/tests/e2e/package.json b/tests/e2e/package.json index a5fa05d5a3b..77616de8be6 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -1,51 +1,73 @@ { - "name": "@eclipse-che/che-e2e", - "version": "7.72.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.91.0-next", + "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", + "delayed-test": "npm run lint && npm run tsc && export TS_USE_WEB_DRIVER_FOR_TEST=false && export MOCHA_DELAYED_SUITE=true && mocha --config dist/configs/mocharc.js --delay", + "open-allure-dasboard": "allure generate .allure-results --clean -o .allure-report && allure open .allure-report", + "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", + "functional-test-suite": "configs/sh-scripts/runFunctionalTests.sh", + "devfile-acceptance-test-suite": "configs/sh-scripts/runDevfileAcceptanceTests.sh" + }, + "author": "Ihor Okhrimenko (iokhrime@redhat.com)", + "license": "ISC", + "devDependencies": { + "@eclipse-che/che-devworkspace-generator": "next", + "@reportportal/agent-js-mocha": "^5.0.3", + "@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", + "allure-commandline": "^2.22.1", + "allure-decorators": "^2.4.0", + "allure-js-commons": "^2.4.0", + "allure-mocha": "^2.4.0", + "axios": "^0.25.0", + "chai": "^4.3.4", + "chrome-har": "^0.13.2", + "chromedriver": "^125.0.0", + "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", + "inversify-inject-decorators": "^3.1.0", + "mocha": "^9.1.3", + "mocha-allure-reporter": "^1.4.0", + "mocha-multi-reporters": "^1.5.1", + "monaco-page-objects": "3.9.1", + "prettier": "^3.0.2", + "rimraf": "2.6.2", + "selenium-webdriver": "4.6.1", + "shelljs": "^0.8.5", + "ts-node": "^10.9.1", + "typescript": "4.9.4", + "vscode-extension-tester-locators": "3.7.1", + "yaml": "^2.2.2" + }, + "dependencies": { + "@eclipse-che/api": "latest", + "inversify": "6.0.1", + "reflect-metadata": "0.1.13" + }, + "resolutions": { + "minimist": "^1.2.5" + } } diff --git a/tests/e2e/package.json.orig b/tests/e2e/package.json.orig new file mode 100644 index 00000000000..740bab17574 --- /dev/null +++ b/tests/e2e/package.json.orig @@ -0,0 +1,125 @@ +{ +<<<<<<< HEAD + "name": "@eclipse-che/che-e2e", + "version": "7.72.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.91.0-next", + "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", + "delayed-test": "npm run lint && npm run tsc && export TS_USE_WEB_DRIVER_FOR_TEST=false && export MOCHA_DELAYED_SUITE=true && mocha --config dist/configs/mocharc.js --delay", + "open-allure-dasboard": "allure generate .allure-results --clean -o .allure-report && allure open .allure-report", + "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", + "functional-test-suite": "configs/sh-scripts/runFunctionalTests.sh", + "devfile-acceptance-test-suite": "configs/sh-scripts/runDevfileAcceptanceTests.sh" + }, + "author": "Ihor Okhrimenko (iokhrime@redhat.com)", + "license": "ISC", + "devDependencies": { + "@eclipse-che/che-devworkspace-generator": "next", + "@reportportal/agent-js-mocha": "^5.0.3", + "@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", + "allure-commandline": "^2.22.1", + "allure-decorators": "^2.4.0", + "allure-js-commons": "^2.4.0", + "allure-mocha": "^2.4.0", + "axios": "^0.25.0", + "chai": "^4.3.4", + "chrome-har": "^0.13.2", + "chromedriver": "^125.0.0", + "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", + "inversify-inject-decorators": "^3.1.0", + "mocha": "^9.1.3", + "mocha-allure-reporter": "^1.4.0", + "mocha-multi-reporters": "^1.5.1", + "monaco-page-objects": "3.9.1", + "prettier": "^3.0.2", + "rimraf": "2.6.2", + "selenium-webdriver": "4.6.1", + "shelljs": "^0.8.5", + "ts-node": "^10.9.1", + "typescript": "4.9.4", + "vscode-extension-tester-locators": "3.7.1", + "yaml": "^2.2.2" + }, + "dependencies": { + "@eclipse-che/api": "latest", + "inversify": "6.0.1", + "reflect-metadata": "0.1.13" + }, + "resolutions": { + "minimist": "^1.2.5" + } +>>>>>>> main +} diff --git a/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts b/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts index 83e463cc067..0b817e9492a 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 @@ -8,90 +8,133 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { injectable, inject } from 'inversify'; +import { inject, injectable } from 'inversify'; 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'; +import { TrustAuthorPopup } from './TrustAuthorPopup'; @injectable() export class CreateWorkspace { - static readonly FACTORY_URL_LOCATOR: By = By.xpath(`//input[@id="git-repo-url"]`); + private static readonly FACTORY_URL: By = By.xpath('//input[@id="git-repo-url"]'); + private static readonly GIT_REPO_OPTIONS: By = By.xpath('//span[text()="Git Repo Options"]'); + private static readonly GIT_BRANCH_NAME: By = By.xpath('//input[@aria-label="Git Branch"]'); + private static readonly PATH_TO_DEVFILE: By = By.xpath('//input[@aria-label="Path to Devfile"]'); + private static readonly CREATE_AND_OPEN_BUTTON: By = By.xpath('//button[@id="create-and-open-button"]'); - 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(`CreateWorkspace.waitTitleContains text: "${expectedText}"`); + @inject(CLASSES.TrustAuthorPopup) + private readonly trustAuthorPopup: TrustAuthorPopup + ) {} - const pageTitleLocator: By = By.xpath(`//h1[contains(text(), '${expectedText}')]`); + async waitTitleContains(expectedText: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(`text: "${expectedText}"`); - await this.driverHelper.waitVisibility(pageTitleLocator, timeout); - } + const pageTitleLocator: By = By.xpath(`//h1[contains(text(), '${expectedText}')]`); - async waitPage(timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug('CreateWorkspace.waitPage'); + await this.driverHelper.waitVisibility(pageTitleLocator, timeout); + } - await this.waitTitleContains('Create Workspace', timeout); - } + async waitPage(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); - async clickOnSampleNoEditorSelection(sampleName: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(`CreateWorkspace.clickOnSample sampleName: "${sampleName}"`); + await this.waitTitleContains('Create Workspace', timeout); + } - const sampleLocator: By = this.getSampleLocator(sampleName); + async clickOnSampleNoEditorSelection( + sampleName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + Logger.debug(`sampleName: "${sampleName}"`); - await this.driverHelper.waitAndClick(sampleLocator, timeout); - } + const sampleLocator: By = this.getSampleLocator(sampleName); - async clickOnSampleForSpecificEditor(sampleName: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - await this.clickOnEditorsDropdownListButton(sampleName, timeout); + await this.driverHelper.waitAndClick(sampleLocator, timeout); + } - Logger.debug(`CreateWorkspace.clickOnSampleForSpecificEditor sampleName: "${sampleName}"`); + async clickOnSampleForSpecificEditor( + sampleName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + await this.clickOnEditorsDropdownListButton(sampleName, timeout); - const sampleLocator: By = this.getSampleLocatorWithSpecificEditor(sampleName); - await this.driverHelper.waitAndClick(sampleLocator, timeout); - } + Logger.debug(`sampleName: "${sampleName}"`); - async importFromGitUsingUI(factoryUrl: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(`CreateWorkspace.importFromGitUsingUI 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); - } + const sampleLocator: By = this.getSampleWithSpecificEditorLocator(sampleName); + await this.driverHelper.waitAndClick(sampleLocator, timeout); + } - private async clickOnEditorsDropdownListButton(sampleName: string, timeout: number): Promise { - Logger.debug(`CreateWorkspace.clickOnSample sampleName: "${sampleName}, editor ${BaseTestConstants.TS_SELENIUM_EDITOR}"`); + async importFromGitUsingUI( + factoryUrl: string, + branchName?: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + Logger.debug(`factoryUrl: "${factoryUrl}"`); - const editorDropdownListLocator: By = this.getEditorsDropdownListLocator(sampleName); - await this.driverHelper.waitAndClick(editorDropdownListLocator, timeout); - } + await this.driverHelper.waitVisibility(CreateWorkspace.FACTORY_URL, timeout); + await this.driverHelper.type(CreateWorkspace.FACTORY_URL, Key.chord(factoryUrl), timeout); - private getEditorsDropdownListLocator(sampleName: string): By { - return By.xpath(`//div[text()=\'${sampleName}\']//parent::article//button`); - } + if (branchName) { + await this.driverHelper.waitAndClick(CreateWorkspace.GIT_REPO_OPTIONS, timeout); - 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}`); - } + await this.driverHelper.waitVisibility(CreateWorkspace.GIT_BRANCH_NAME, timeout); + await this.driverHelper.type(CreateWorkspace.GIT_BRANCH_NAME, Key.chord(branchName, Key.ENTER), timeout); + } - Logger.trace(`CreateWorkspace.getSampleLocatorWithSpecificEditor sampleName: ${sampleName}, editor "${editor}"`); + await this.driverHelper.waitAndClick(CreateWorkspace.CREATE_AND_OPEN_BUTTON, timeout); - return By.xpath(`//div[text()='${sampleName}']//parent::article//span[text()[ + await this.performTrustAuthorPopup(); + } + + 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); + } + + async performTrustAuthorPopup(): Promise { + Logger.debug(); + + try { + await this.trustAuthorPopup.clickContinue(); + } catch (e) { + Logger.info('"Trust author" popup was not shown'); + } + } + + private getEditorsDropdownListLocator(sampleName: string): By { + return By.xpath(`//div[text()=\'${sampleName}\']//parent::article//button`); + } + + private getSampleWithSpecificEditorLocator(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}"`); + + return By.xpath(`//div[text()='${sampleName}']//parent::article//span[text()[ contains( translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '${editor}')] ]//parent::a`); - } + } - private getSampleLocator(sampleName: string): By { - Logger.trace(`CreateWorkspace.getSampleLocator 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/CreateWorkspace.ts.orig b/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts.orig new file mode 100644 index 00000000000..af886489273 --- /dev/null +++ b/tests/e2e/pageobjects/dashboard/CreateWorkspace.ts.orig @@ -0,0 +1,150 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { inject, injectable } from 'inversify'; +import { CLASSES } from '../../configs/inversify.types'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { By, Key } from 'selenium-webdriver'; +import { Logger } from '../../utils/Logger'; +<<<<<<< HEAD +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'; +import { TrustAuthorPopup } from './TrustAuthorPopup'; +>>>>>>> main + +@injectable() +export class CreateWorkspace { + private static readonly FACTORY_URL: By = By.xpath('//input[@id="git-repo-url"]'); + private static readonly GIT_REPO_OPTIONS: By = By.xpath('//span[text()="Git Repo Options"]'); + private static readonly GIT_BRANCH_NAME: By = By.xpath('//input[@aria-label="Git Branch"]'); + private static readonly PATH_TO_DEVFILE: By = By.xpath('//input[@aria-label="Path to Devfile"]'); + private static readonly CREATE_AND_OPEN_BUTTON: By = By.xpath('//button[@id="create-and-open-button"]'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper, + + @inject(CLASSES.TrustAuthorPopup) + private readonly trustAuthorPopup: TrustAuthorPopup + ) {} + + 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}')]`); + + await this.driverHelper.waitVisibility(pageTitleLocator, timeout); + } + + async waitPage(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); + + await this.waitTitleContains('Create Workspace', timeout); + } + + async clickOnSampleNoEditorSelection( + sampleName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + Logger.debug(`sampleName: "${sampleName}"`); + + const sampleLocator: By = this.getSampleLocator(sampleName); + + await this.driverHelper.waitAndClick(sampleLocator, timeout); + } + + async clickOnSampleForSpecificEditor( + sampleName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + await this.clickOnEditorsDropdownListButton(sampleName, timeout); + + Logger.debug(`sampleName: "${sampleName}"`); + + const sampleLocator: By = this.getSampleWithSpecificEditorLocator(sampleName); + await this.driverHelper.waitAndClick(sampleLocator, timeout); + } + +<<<<<<< HEAD + private async clickOnEditorsDropdownListButton(sampleName: string, timeout: number): Promise { + Logger.debug(`CreateWorkspace.clickOnSample sampleName: "${sampleName}, editor ${BaseTestConstants.TS_SELENIUM_EDITOR}"`); +======= + async importFromGitUsingUI( + factoryUrl: string, + branchName?: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + Logger.debug(`factoryUrl: "${factoryUrl}"`); +>>>>>>> main + + await this.driverHelper.waitVisibility(CreateWorkspace.FACTORY_URL, timeout); + await this.driverHelper.type(CreateWorkspace.FACTORY_URL, Key.chord(factoryUrl), timeout); + + if (branchName) { + await this.driverHelper.waitAndClick(CreateWorkspace.GIT_REPO_OPTIONS, timeout); + + await this.driverHelper.waitVisibility(CreateWorkspace.GIT_BRANCH_NAME, timeout); + await this.driverHelper.type(CreateWorkspace.GIT_BRANCH_NAME, Key.chord(branchName, Key.ENTER), timeout); + } + + await this.driverHelper.waitAndClick(CreateWorkspace.CREATE_AND_OPEN_BUTTON, timeout); + + await this.performTrustAuthorPopup(); + } + + 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); + } + + async performTrustAuthorPopup(): Promise { + Logger.debug(); + + try { + await this.trustAuthorPopup.clickContinue(); + } catch (e) { + Logger.info('"Trust author" popup was not shown'); + } + } + + private getEditorsDropdownListLocator(sampleName: string): By { + return By.xpath(`//div[text()=\'${sampleName}\']//parent::article//button`); + } + + private getSampleWithSpecificEditorLocator(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}"`); + + 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`); + + 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 4e3eb8f1317..15b001a459d 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,135 +12,183 @@ 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 { OAuthConstants } from '../../constants/OAuthConstants'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; @injectable() export class Dashboard { - private static readonly WORKSPACES_BUTTON_XPATH: string = `//div[@id='page-sidebar']//a[contains(text(), 'Workspaces (')]`; - private static readonly CREATE_WORKSPACE_BUTTON_XPATH: string = `//div[@id='page-sidebar']//a[text()='Create Workspace']`; - private static readonly LOADER_PAGE_STEP_TITLES_XPATH: string = '//*[@data-testid="step-title"]'; - private static readonly STARTING_PAGE_LOADER_CSS: string = '.main-page-loader'; - private static readonly LOADER_ALERT_XPATH: string = '//*[@data-testid="loader-alert"]'; - private static readonly LOGOUT_BUTTON_XPATH: string = '//button[text()="Logout"]'; + 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'); + private static readonly INFO_DROPDOWN_BUTTON: By = By.xpath('//button[@aria-label="About Menu"]'); + private static readonly ABOUT_DIALOG_WINDOW_CLOSE_BUTTON: By = By.xpath('//button[@aria-label="Close Dialog"]'); + private static readonly EXISTING_WORKSPACE_FOUND_ALERT: By = By.xpath('//h4[text()="Existing workspace found"]'); + private static readonly CREATE_NEW_WORKSPACE_LINK: By = By.xpath('//button[text()="Create a new workspace"]'); + private static readonly ABOUT_DIALOG_ITEM_DATA_TEST_IDS: any = { + serverVersion: 'server-version', + dashboardVersion: 'dashboard-version', + browserName: 'browser-name', + browserOs: 'browser-os', + browserVersion: 'browser-version', + username: 'username' + }; + + constructor( + @inject(CLASSES.DriverHelper) + 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}"`); - private static getUserDropdownMenuButtonLocator(): By { - Logger.debug(`Dashboard.getUserDropdownMenuButtonLocator: get current user.`); + await this.stopWorkspaceByUI(workspaceName); + await this.deleteStoppedWorkspaceByUI(workspaceName); + } - const currentUser: string = OAuthConstants.TS_SELENIUM_OCP_USERNAME; - Logger.debug(`Dashboard.getUserDropdownMenuButtonLocator: ${currentUser}.`); + async openDashboard(): Promise { + Logger.debug(); - return By.xpath(`//*[text()="${currentUser}"]//parent::button`); + await this.driverHelper.navigateToUrl(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL); + await this.waitPage(); + } - } + async openAboutMenu(): Promise { + Logger.debug(); - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, - @inject(CLASSES.Workspaces) private readonly workspaces: Workspaces) { - } + await this.driverHelper.waitAndClick(Dashboard.INFO_DROPDOWN_BUTTON); + } + + async selectAboutMenuItem(text: string): Promise { + Logger.debug(); - async stopWorkspaceByUI(workspaceName: string): Promise { - Logger.debug(`Dashboard.stopWorkspaceByUI "${workspaceName}"`); + await this.driverHelper.waitAndClick(this.getAboutMenuItemButtonLocator(text)); + } + + async waitAboutDialogWindowMenuElements(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + for (const testId of Object.values(Dashboard.ABOUT_DIALOG_ITEM_DATA_TEST_IDS)) { + const workspaceDetailsTabLocator: By = this.getAboutDialogWindowItemLocator(testId); + + await this.driverHelper.waitVisibility(workspaceDetailsTabLocator, timeout); + } + } + + async getApplicationVersionFromAboutDialogWindow(): Promise { + Logger.debug(); + + return await this.driverHelper.waitAndGetText( + this.getAboutDialogWindowItemLocator(Dashboard.ABOUT_DIALOG_ITEM_DATA_TEST_IDS.serverVersion) + ); + } + + async getUsernameFromAboutDialogWindow(): Promise { + Logger.debug(); + + return await this.driverHelper.waitAndGetText( + this.getAboutDialogWindowItemLocator(Dashboard.ABOUT_DIALOG_ITEM_DATA_TEST_IDS.username) + ); + } + + async waitPage(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); - await this.clickWorkspacesButton(); - await this.workspaces.waitPage(); - await this.workspaces.waitWorkspaceListItem(workspaceName); - await this.workspaces.waitWorkspaceWithRunningStatus(workspaceName); + await this.driverHelper.waitVisibility(Dashboard.WORKSPACES_BUTTON, timeout); + await this.driverHelper.waitVisibility(Dashboard.CREATE_WORKSPACE_BUTTON, timeout); + } - await this.workspaces.stopWorkspaceByActionsButton(workspaceName); - await this.workspaces.waitWorkspaceWithStoppedStatus(workspaceName); - } + async clickWorkspacesButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); - async deleteStoppedWorkspaceByUI(workspaceName: string): Promise { - Logger.debug(`Dashboard.deleteStoppedWorkspaceByUI "${workspaceName}"`); + await this.driverHelper.waitAndClick(Dashboard.WORKSPACES_BUTTON, timeout); + } - 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 clickCreateWorkspaceButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); - async stopAndRemoveWorkspaceByUI(workspaceName: string): Promise { - Logger.debug(`Dashboard.stopAndRemoveWorkspaceByUI "${workspaceName}"`); + await this.driverHelper.waitAndClick(Dashboard.CREATE_WORKSPACE_BUTTON, timeout); + } - await this.stopWorkspaceByUI(workspaceName); - await this.workspaces.deleteWorkspaceByActionsButton(workspaceName); - await this.workspaces.waitWorkspaceListItemAbsence(workspaceName); - } + async getLoaderAlert(timeout: number = TIMEOUT_CONSTANTS.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { + Logger.debug(); - async openDashboard(): Promise { - Logger.debug('Dashboard.openDashboard'); - await this.driverHelper.getDriver().navigate().to(BaseTestConstants.TS_SELENIUM_BASE_URL); - await this.waitPage(); + return await this.driverHelper.waitAndGetText(Dashboard.LOADER_ALERT, timeout); + } - } + async waitLoader(timeout: number = TIMEOUT_CONSTANTS.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { + Logger.debug(); - async waitPage(timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug('Dashboard.waitPage'); + await this.driverHelper.waitAllPresence(Dashboard.LOADER_PAGE_STEP_TITLES, timeout); + } - await this.driverHelper.waitVisibility(By.xpath(Dashboard.WORKSPACES_BUTTON_XPATH), timeout); - await this.driverHelper.waitVisibility(By.xpath(Dashboard.CREATE_WORKSPACE_BUTTON_XPATH), timeout); - } + async waitStartingPageLoaderDisappearance(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); - async clickWorkspacesButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug('Dashboard.clickWorkspacesButton'); + await this.driverHelper.waitDisappearance(Dashboard.STARTING_PAGE_LOADER, timeout); + await this.driverHelper.wait(TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING); + } - await this.driverHelper.waitAndClick(By.xpath(Dashboard.WORKSPACES_BUTTON_XPATH), timeout); - } + async closeAboutDialogWindow(): Promise { + Logger.debug(); - async clickCreateWorkspaceButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug('Dashboard.clickCreateWorkspaceButton'); + await this.driverHelper.waitAndClick(Dashboard.ABOUT_DIALOG_WINDOW_CLOSE_BUTTON); + } - await this.driverHelper.waitAndClick(By.xpath(Dashboard.CREATE_WORKSPACE_BUTTON_XPATH), timeout); - } + async waitExistingWorkspaceFoundAlert(timeout: number = TIMEOUT_CONSTANTS.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { + Logger.debug(); - async getLoaderAlert(timeout: number = TimeoutConstants.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { - Logger.debug('Dashboard.getLoaderAlert'); + await this.driverHelper.waitVisibility(Dashboard.EXISTING_WORKSPACE_FOUND_ALERT, timeout); + } - return await this.driverHelper.waitAndGetText(By.xpath(Dashboard.LOADER_ALERT_XPATH), timeout); - } + async clickOnCreateNewWorkspaceButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); - async waitLoader(timeout: number = TimeoutConstants.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { - Logger.debug('Dashboard.waitLoader'); + await this.driverHelper.waitAndClick(Dashboard.CREATE_NEW_WORKSPACE_LINK, timeout); + } - await this.driverHelper.waitAllPresence(By.xpath(Dashboard.LOADER_PAGE_STEP_TITLES_XPATH), timeout); - } + async logout(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); - async waitLoaderDisappearance(timeout: number = TimeoutConstants.TS_WAIT_LOADER_ABSENCE_TIMEOUT): Promise { - Logger.debug('Dashboard.waitLoaderDisappearance'); + 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); + } - await this.driverHelper.waitDisappearance(By.xpath(Dashboard.LOADER_PAGE_STEP_TITLES_XPATH), timeout); - } + private getAboutMenuItemButtonLocator(text: string): By { + return By.xpath(`//li/button[text()="${text}"]`); + } - async waitDisappearanceNavigationMenu(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug('Dashboard.waitDisappearanceNavigationMenu'); - - await this.driverHelper.waitDisappearance(By.id('chenavmenu'), timeout); - } - - async waitStartingPageLoaderDisappearance(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`Dashboard.waitStartingPageLoaderDisappearance`); - - await this.driverHelper.waitDisappearance(By.css(Dashboard.STARTING_PAGE_LOADER_CSS), timeout); - await this.driverHelper.wait(TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING); - } - - async getRecentWorkspaceName(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`Dashboard.getRecentWorkspaceName`); - - return await this.driverHelper.waitAndGetText(By.css('[data-testid="recent-workspace-item"]'), timeout); - } - - async logout(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`Dashboard.logout`); - - await this.openDashboard(); - await this.driverHelper.waitAndClick(Dashboard.getUserDropdownMenuButtonLocator(), timeout); - await this.driverHelper.waitAndClick(By.xpath(Dashboard.LOGOUT_BUTTON_XPATH), timeout); - await this.driverHelper.waitDisappearance(Dashboard.getUserDropdownMenuButtonLocator(), timeout); - } + private getAboutDialogWindowItemLocator(itemDataTestId: string): By { + return By.xpath(`//dd[@data-testid="${itemDataTestId}"]`); + } } diff --git a/tests/e2e/pageobjects/dashboard/Dashboard.ts.orig b/tests/e2e/pageobjects/dashboard/Dashboard.ts.orig new file mode 100644 index 00000000000..f966d0bab1a --- /dev/null +++ b/tests/e2e/pageobjects/dashboard/Dashboard.ts.orig @@ -0,0 +1,235 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { inject, injectable } from 'inversify'; +import 'reflect-metadata'; +import { CLASSES } from '../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { DriverHelper } from '../../utils/DriverHelper'; +<<<<<<< HEAD +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { Workspaces } from './Workspaces'; +import { Logger } from '../../utils/Logger'; +import { OAuthConstants } from '../../constants/OAuthConstants'; +import { BaseTestConstants } from '../../constants/BaseTestConstants'; +======= +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +import { Workspaces } from './Workspaces'; +import { Logger } from '../../utils/Logger'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +>>>>>>> main + +@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'); + private static readonly INFO_DROPDOWN_BUTTON: By = By.xpath('//button[@aria-label="About Menu"]'); + private static readonly ABOUT_DIALOG_WINDOW_CLOSE_BUTTON: By = By.xpath('//button[@aria-label="Close Dialog"]'); + private static readonly EXISTING_WORKSPACE_FOUND_ALERT: By = By.xpath('//h4[text()="Existing workspace found"]'); + private static readonly CREATE_NEW_WORKSPACE_LINK: By = By.xpath('//button[text()="Create a new workspace"]'); + private static readonly ABOUT_DIALOG_ITEM_DATA_TEST_IDS: any = { + serverVersion: 'server-version', + dashboardVersion: 'dashboard-version', + browserName: 'browser-name', + browserOs: 'browser-os', + browserVersion: 'browser-version', + username: 'username' + }; + + constructor( + @inject(CLASSES.DriverHelper) + readonly driverHelper: DriverHelper, + @inject(CLASSES.Workspaces) private readonly workspaces: Workspaces + ) {} + +<<<<<<< HEAD + const currentUser: string = OAuthConstants.TS_SELENIUM_OCP_USERNAME; + Logger.debug(`Dashboard.getUserDropdownMenuButtonLocator: ${currentUser}.`); +======= + async stopWorkspaceByUI(workspaceName: string): Promise { + Logger.debug(`"${workspaceName}"`); +>>>>>>> main + + 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.deleteStoppedWorkspaceByUI(workspaceName); + } + + async openDashboard(): Promise { + Logger.debug(); + + await this.driverHelper.navigateToUrl(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL); + await this.waitPage(); + } + +<<<<<<< HEAD + 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 openAboutMenu(): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.waitAndClick(Dashboard.INFO_DROPDOWN_BUTTON); + } + +<<<<<<< HEAD + await this.stopWorkspaceByUI(workspaceName); + await this.workspaces.deleteWorkspaceByActionsButton(workspaceName); + await this.workspaces.waitWorkspaceListItemAbsence(workspaceName); + } + + async openDashboard(): Promise { + Logger.debug('Dashboard.openDashboard'); + await this.driverHelper.getDriver().navigate().to(BaseTestConstants.TS_SELENIUM_BASE_URL); + await this.waitPage(); +======= + async selectAboutMenuItem(text: string): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(this.getAboutMenuItemButtonLocator(text)); + } +>>>>>>> main + + async waitAboutDialogWindowMenuElements(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + for (const testId of Object.values(Dashboard.ABOUT_DIALOG_ITEM_DATA_TEST_IDS)) { + const workspaceDetailsTabLocator: By = this.getAboutDialogWindowItemLocator(testId); + + await this.driverHelper.waitVisibility(workspaceDetailsTabLocator, timeout); + } + } + + async getApplicationVersionFromAboutDialogWindow(): Promise { + Logger.debug(); + + return await this.driverHelper.waitAndGetText( + this.getAboutDialogWindowItemLocator(Dashboard.ABOUT_DIALOG_ITEM_DATA_TEST_IDS.serverVersion) + ); + } + + async getUsernameFromAboutDialogWindow(): Promise { + Logger.debug(); + + return await this.driverHelper.waitAndGetText( + this.getAboutDialogWindowItemLocator(Dashboard.ABOUT_DIALOG_ITEM_DATA_TEST_IDS.username) + ); + } + + 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(); + +<<<<<<< HEAD + await this.driverHelper.waitDisappearance(By.css(Dashboard.STARTING_PAGE_LOADER_CSS), timeout); + await this.driverHelper.wait(TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING); + } +======= + await this.driverHelper.waitAllPresence(Dashboard.LOADER_PAGE_STEP_TITLES, timeout); + } +>>>>>>> main + + 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 closeAboutDialogWindow(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(Dashboard.ABOUT_DIALOG_WINDOW_CLOSE_BUTTON); + } + + async waitExistingWorkspaceFoundAlert(timeout: number = TIMEOUT_CONSTANTS.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(Dashboard.EXISTING_WORKSPACE_FOUND_ALERT, timeout); + } + + async clickOnCreateNewWorkspaceButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(Dashboard.CREATE_NEW_WORKSPACE_LINK, timeout); + } + + 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); + } + + private getAboutMenuItemButtonLocator(text: string): By { + return By.xpath(`//li/button[text()="${text}"]`); + } + + private getAboutDialogWindowItemLocator(itemDataTestId: string): By { + return By.xpath(`//dd[@data-testid="${itemDataTestId}"]`); + } +} diff --git a/tests/e2e/pageobjects/dashboard/TrustAuthorPopup.ts b/tests/e2e/pageobjects/dashboard/TrustAuthorPopup.ts new file mode 100644 index 00000000000..4d00c703cd8 --- /dev/null +++ b/tests/e2e/pageobjects/dashboard/TrustAuthorPopup.ts @@ -0,0 +1,42 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { inject, injectable } from 'inversify'; +import 'reflect-metadata'; +import { CLASSES } from '../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { Logger } from '../../utils/Logger'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; + +@injectable() +export class TrustAuthorPopup { + private static readonly CONTINUE_BUTTON: By = By.xpath('//button[text()="Continue"]'); + private static readonly TRUST_AUTHOR_POPUP_PAGE: By = By.xpath( + '//span[contains(text(), "Do you trust the authors of this repository?")]' + ); + + constructor( + @inject(CLASSES.DriverHelper) + readonly driverHelper: DriverHelper + ) {} + + async clickContinue(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + Logger.debug(); + + await this.waitPopupIsOpened(); + await this.driverHelper.waitAndClick(TrustAuthorPopup.CONTINUE_BUTTON, timeout); + } + + async waitPopupIsOpened(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(TrustAuthorPopup.TRUST_AUTHOR_POPUP_PAGE, timeout); + } +} diff --git a/tests/e2e/pageobjects/dashboard/UserPreferences.ts b/tests/e2e/pageobjects/dashboard/UserPreferences.ts new file mode 100644 index 00000000000..9e074e7bc48 --- /dev/null +++ b/tests/e2e/pageobjects/dashboard/UserPreferences.ts @@ -0,0 +1,138 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { inject, injectable } from 'inversify'; +import 'reflect-metadata'; +import { CLASSES } from '../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { Logger } from '../../utils/Logger'; +import { GitProviderType } from '../../constants/FACTORY_TEST_CONSTANTS'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; + +@injectable() +export class UserPreferences { + private static readonly USER_SETTINGS_DROPDOWN: By = By.xpath('//header//button/span[text()!=""]//parent::button'); + private static readonly USER_PREFERENCES_BUTTON: By = By.xpath('//button[text()="User Preferences"]'); + private static readonly USER_PREFERENCES_PAGE: By = By.xpath('//h1[text()="User Preferences"]'); + + private static readonly CONTAINER_REGISTRIES_TAB: By = By.xpath('//button[text()="Container Registries"]'); + + private static readonly GIT_SERVICES_TAB: By = By.xpath('//button[text()="Git Services"]'); + private static readonly GIT_SERVICES_REVOKE_BUTTON: By = By.xpath('//button[text()="Revoke"]'); + + private static readonly PAT_TAB: By = By.xpath('//button[text()="Personal Access Tokens"]'); + private static readonly ADD_NEW_PAT_BUTTON: By = By.xpath('//button[text()="Add Personal Access Token"]'); + + private static readonly GIT_CONFIG_PAGE: By = By.xpath('//button[text()="Gitconfig"]'); + + private static readonly SSH_KEY_TAB: By = By.xpath('//button[text()="SSH Keys"]'); + private static readonly ADD_NEW_SSH_KEY_BUTTON: By = By.xpath('//button[text()="Add SSH Key"]'); + + private static readonly CONFIRMATION_WINDOW: By = By.xpath('//span[text()="Revoke Git Services"]'); + private static readonly DELETE_CONFIRMATION_CHECKBOX: By = By.xpath('//input[@data-testid="warning-info-checkbox"]'); + private static readonly DELETE_ITEM_BUTTON_ENABLED: By = By.xpath('//button[@data-testid="revoke-button" and not(@disabled)]'); + + constructor( + @inject(CLASSES.DriverHelper) + readonly driverHelper: DriverHelper + ) {} + + async openUserPreferencesPage(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(UserPreferences.USER_SETTINGS_DROPDOWN); + await this.driverHelper.waitAndClick(UserPreferences.USER_PREFERENCES_BUTTON); + + await this.driverHelper.waitVisibility(UserPreferences.USER_PREFERENCES_PAGE); + } + + async checkTabsAvailability(): Promise { + Logger.debug(); + + await this.openContainerRegistriesTab(); + await this.openGitServicesTab(); + await this.openPatTab(); + await this.openGitConfigPage(); + await this.openSshKeyTab(); + } + + async openContainerRegistriesTab(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(UserPreferences.CONTAINER_REGISTRIES_TAB); + } + + async openGitServicesTab(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(UserPreferences.GIT_SERVICES_TAB); + } + + async revokeGitService(servicesName: string): Promise { + Logger.debug(); + + await this.selectListItem(servicesName); + await this.driverHelper.waitAndClick(UserPreferences.GIT_SERVICES_REVOKE_BUTTON); + + await this.driverHelper.waitVisibility(UserPreferences.CONFIRMATION_WINDOW); + await this.driverHelper.waitAndClick(UserPreferences.DELETE_CONFIRMATION_CHECKBOX); + await this.driverHelper.waitAndClick(UserPreferences.DELETE_ITEM_BUTTON_ENABLED); + + await this.driverHelper.waitAttributeValue( + this.getServicesListItemLocator(servicesName), + 'disabled', + 'true', + TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ); + } + + async selectListItem(servicesName: string): Promise { + Logger.debug(`of the '${servicesName}' list item`); + + await this.driverHelper.waitAndClick(this.getServicesListItemLocator(servicesName)); + } + + async openPatTab(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(UserPreferences.PAT_TAB); + await this.driverHelper.waitVisibility(UserPreferences.ADD_NEW_PAT_BUTTON); + } + + async openGitConfigPage(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(UserPreferences.GIT_CONFIG_PAGE); + } + + async openSshKeyTab(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(UserPreferences.SSH_KEY_TAB); + await this.driverHelper.waitVisibility(UserPreferences.ADD_NEW_SSH_KEY_BUTTON); + } + + getServiceConfig(service: string): string { + const gitService: { [key: string]: string } = { + [GitProviderType.GITHUB]: 'GitHub', + [GitProviderType.GITLAB]: 'GitLab', + [GitProviderType.AZURE_DEVOPS]: 'Microsoft Azure DevOps', + [GitProviderType.BITBUCKET_CLOUD_OAUTH2]: 'Bitbucket Cloud', + [GitProviderType.BITBUCKET_SERVER_OAUTH1]: 'Bitbucket Server', + [GitProviderType.BITBUCKET_SERVER_OAUTH2]: 'Bitbucket Server' + }; + + return gitService[service]; + } + + private getServicesListItemLocator(servicesName: string): By { + return By.xpath(`//tr[td[text()='${servicesName}']]//input`); + } +} diff --git a/tests/e2e/pageobjects/dashboard/Workspaces.ts b/tests/e2e/pageobjects/dashboard/Workspaces.ts index e06c2b2e123..7eb00f09d97 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 @@ -8,208 +8,242 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { injectable, inject } from 'inversify'; +import { inject, injectable } from 'inversify'; 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 = 'Workspace status is Running', + Stopped = 'Workspace status is Stopped' } @injectable() export class Workspaces { - private static readonly ADD_WORKSPACE_BUTTON_XPATH: string = `//button[text()='Add Workspace']`; - private static readonly WORKSPACE_ITEM_TABLE_NAME_SECTION_XPATH: string = `//td[@data-label="Name"]/span/a`; + private static readonly ADD_WORKSPACE_BUTTON: By = By.xpath('//button[text()="Add Workspace"]'); + private static readonly WORKSPACE_ITEM_TABLE_NAME_SECTION: By = By.xpath('//td[@data-label="Name"]/span/a'); + private static readonly DELETE_WORKSPACE_BUTTON_ENABLED: By = By.xpath( + '//button[@data-testid="delete-workspace-button" and not(@disabled)]' + ); + private static readonly DELETE_CONFIRMATION_CHECKBOX: By = By.xpath('//input[@data-testid="confirmation-checkbox"]'); + private static readonly CONFIRMATION_WINDOW: By = By.xpath('//div[@aria-label="Delete workspaces confirmation window"]'); + private static readonly LEARN_MORE_DOC_LINK: By = By.xpath('//div/p/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('Workspaces.waitPage'); + async waitPage(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); - await this.driverHelper.waitVisibility(By.xpath(Workspaces.ADD_WORKSPACE_BUTTON_XPATH), timeout); - } + await this.driverHelper.waitVisibility(Workspaces.ADD_WORKSPACE_BUTTON, timeout); + } - async clickAddWorkspaceButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug('Workspaces.clickAddWorkspaceButton'); + async clickAddWorkspaceButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); - await this.driverHelper.waitAndClick(By.xpath(Workspaces.ADD_WORKSPACE_BUTTON_XPATH), timeout); - } + await this.driverHelper.waitAndClick(Workspaces.ADD_WORKSPACE_BUTTON, timeout); + } - async clickOpenButton(workspaceName: string, timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug('Workspaces.clickOpenButton'); + 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(`Workspaces.waitWorkspaceListItem "${workspaceName}"`); - - const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); - - await this.driverHelper.waitVisibility(workspaceListItemLocator, timeout); - } - - async waitWorkspaceWithRunningStatus(workspaceName: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`Workspaces.waitWorkspaceWithRunningStatus "${workspaceName}"`); - - const runningStatusLocator: By = this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Running); - - await this.driverHelper.waitVisibility(runningStatusLocator, timeout); - } - - async waitWorkspaceWithStoppedStatus(workspaceName: string, timeout: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug(`Workspaces.waitWorkspaceWithStoppedStatus "${workspaceName}"`); - - const stoppedStatusLocator: By = this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Stopped); - - await this.driverHelper.waitVisibility(stoppedStatusLocator, timeout); - } - - async clickWorkspaceListItem(workspaceName: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug(`Workspaces.clickWorkspaceListItem "${workspaceName}"`); - - const workspaceListItemLocator: By = By.xpath(this.getWorkspaceListItemLocator(workspaceName)); - - await this.driverHelper.waitAndClick(workspaceListItemLocator, timeout); - } - - async clickActionsButton(workspaceName: string): Promise { - Logger.debug(`Workspaces.clickActionsButton of the '${workspaceName}' list item`); - - await this.driverHelper.waitAndClick(this.getActionsLocator(workspaceName)); - } - - async waitActionsPopup(workspaceName: string, timeout: number = TimeoutConstants.TS_CONTEXT_MENU_TIMEOUT): Promise { - Logger.debug(`Workspaces.waitActionsPopup of the '${workspaceName}' list item`); - - await this.driverHelper.waitVisibility(this.getExpandedActionsLocator(workspaceName), timeout); - } - - async openActionsPopup(workspaceName: string, timeout: number = TimeoutConstants.TS_CONTEXT_MENU_TIMEOUT): Promise { - Logger.debug(`Workspaces.openActionsPopup for the '${workspaceName}' list item`); - await this.clickActionsButton(workspaceName); - await this.waitActionsPopup(workspaceName, timeout); - } - - async clickActionsDeleteButton(workspaceName: string): Promise { - Logger.debug(`Workspaces.clickActionsDeleteButton for the '${workspaceName}' list item`); - - await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Delete Workspace')); - } - - async clickActionsStopWorkspaceButton(workspaceName: string): Promise { - Logger.debug(`Workspaces.clickActionsStopWorkspaceButton 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(`Workspaces.clickActionsStopWorkspaceButton 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')); - } - } - - async waitDeleteWorkspaceConfirmationWindow(timeout: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { - Logger.debug(`Workspaces.waitDeleteWorkspaceConfirmationWindow`); - - 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']`); - } + async waitWorkspaceListItem( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.driverHelper.waitVisibility(this.getWorkspaceListItemLocator(workspaceName), timeout); + } + + async waitWorkspaceWithRunningStatus( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.driverHelper.waitVisibility(this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Running), timeout); + } + + async waitWorkspaceWithStoppedStatus( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.driverHelper.waitVisibility(this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Stopped), timeout); + } + + async clickWorkspaceListItemLink( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.driverHelper.waitAndClick(this.getOpenWorkspaceDetailsLinkLocator(workspaceName), timeout); + } + + async clickActionsButton(workspaceName: string): Promise { + Logger.debug(`of the '${workspaceName}' list item`); + + await this.driverHelper.waitAndClick(this.getActionsLocator(workspaceName)); + } + + 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); + } + + 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`); + + 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).`); + + await this.driverHelper.waitAndClick(this.getActionsLocator(workspaceName)); + await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Stop Workspace')); + } + } + + async waitDeleteWorkspaceConfirmationWindow(timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(Workspaces.CONFIRMATION_WINDOW, timeout); + } + + async clickToDeleteConfirmationCheckbox(timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(Workspaces.DELETE_CONFIRMATION_CHECKBOX, timeout); + } + + async waitAndClickEnabledConfirmationWindowDeleteButton( + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(Workspaces.DELETE_WORKSPACE_BUTTON_ENABLED, timeout); + } + + async deleteWorkspaceByActionsButton( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug(); + + 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(); + + 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(`"${workspaceName}"`); + + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + await this.driverHelper.waitDisappearance(this.getWorkspaceListItemLocator(workspaceName), attempts, polling); + } + + async getAllCreatedWorkspacesNames(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + const workspaceNames: string[] = []; + try { + const workspaceItems: WebElement[] = await this.driverHelper.waitAllPresence( + Workspaces.WORKSPACE_ITEM_TABLE_NAME_SECTION, + timeout + ); + for (const item of workspaceItems) { + Logger.debug(`try to get ${workspaceItems.indexOf(item)} items name`); + workspaceNames.push(await item.getText()); + Logger.debug(`workspace name is "${workspaceNames[workspaceNames.length - 1]}"`); + } + } catch (e) { + Logger.debug(`${e}`); + } + + Logger.debug(`${workspaceNames.length} workspaces have been created in DevSpaces`); + return workspaceNames; + } + + async getLearnMoreDocumentationLink(): Promise { + Logger.debug(); + + return await this.driverHelper.waitAndGetElementAttribute(Workspaces.LEARN_MORE_DOC_LINK, 'href'); + } + + private getWorkspaceListItemLocator(workspaceName: string): By { + return By.xpath(`//tr[td//a[text()='${workspaceName}']]`); + } + + private getWorkspaceStatusLocator(workspaceName: string, workspaceStatus: WorkspaceStatusUI): By { + return By.xpath( + `${ + this.getWorkspaceListItemLocator(workspaceName).value + }//span[@data-testid='workspace-status-indicator' and @aria-label='${workspaceStatus}']` + ); + } + + private getActionsLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}/td/div/button[@aria-label='Actions']`); + } + + private getExpandedActionsLocator(workspaceName: string): By { + return By.xpath( + `${this.getWorkspaceListItemLocator(workspaceName).value}//button[@aria-label='Actions' and @aria-expanded='true']` + ); + } + + private getActionsPopupButtonLocator(workspaceName: string, buttonText: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}//button[text()='${buttonText}']`); + } + + private getOpenButtonLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}//td[@data-key=5]//a[text()='Open']`); + } + + private getOpenWorkspaceDetailsLinkLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}//a[text()='${workspaceName}']`); + } } diff --git a/tests/e2e/pageobjects/dashboard/Workspaces.ts.orig b/tests/e2e/pageobjects/dashboard/Workspaces.ts.orig new file mode 100644 index 00000000000..00826d4b67b --- /dev/null +++ b/tests/e2e/pageobjects/dashboard/Workspaces.ts.orig @@ -0,0 +1,261 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { inject, injectable } from 'inversify'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { CLASSES } from '../../configs/inversify.types'; +import { By, WebElement } from 'selenium-webdriver'; +import { Logger } from '../../utils/Logger'; +<<<<<<< HEAD +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +======= +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +>>>>>>> main + +export enum WorkspaceStatusUI { + Running = 'Workspace status is Running', + Stopped = 'Workspace status is Stopped' +} + +@injectable() +export class Workspaces { + private static readonly ADD_WORKSPACE_BUTTON: By = By.xpath('//button[text()="Add Workspace"]'); + private static readonly WORKSPACE_ITEM_TABLE_NAME_SECTION: By = By.xpath('//td[@data-label="Name"]/span/a'); + private static readonly DELETE_WORKSPACE_BUTTON_ENABLED: By = By.xpath( + '//button[@data-testid="delete-workspace-button" and not(@disabled)]' + ); + private static readonly DELETE_CONFIRMATION_CHECKBOX: By = By.xpath('//input[@data-testid="confirmation-checkbox"]'); + private static readonly CONFIRMATION_WINDOW: By = By.xpath('//div[@aria-label="Delete workspaces confirmation window"]'); + private static readonly LEARN_MORE_DOC_LINK: By = By.xpath('//div/p/a'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async waitPage(timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(Workspaces.ADD_WORKSPACE_BUTTON, timeout); + } + + async clickAddWorkspaceButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(Workspaces.ADD_WORKSPACE_BUTTON, timeout); + } + + async clickOpenButton(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(this.getOpenButtonLocator(workspaceName), timeout); + } + + async waitWorkspaceListItem( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.driverHelper.waitVisibility(this.getWorkspaceListItemLocator(workspaceName), timeout); + } + + async waitWorkspaceWithRunningStatus( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.driverHelper.waitVisibility(this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Running), timeout); + } + + async waitWorkspaceWithStoppedStatus( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.driverHelper.waitVisibility(this.getWorkspaceStatusLocator(workspaceName, WorkspaceStatusUI.Stopped), timeout); + } + + async clickWorkspaceListItemLink( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT + ): Promise { + Logger.debug(`"${workspaceName}"`); + + await this.driverHelper.waitAndClick(this.getOpenWorkspaceDetailsLinkLocator(workspaceName), timeout); + } + + async clickActionsButton(workspaceName: string): Promise { + Logger.debug(`of the '${workspaceName}' list item`); + + await this.driverHelper.waitAndClick(this.getActionsLocator(workspaceName)); + } + + 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); + } + + 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`); + + 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).`); + + await this.driverHelper.waitAndClick(this.getActionsLocator(workspaceName)); + await this.driverHelper.waitAndClick(this.getActionsPopupButtonLocator(workspaceName, 'Stop Workspace')); + } + } + + async waitDeleteWorkspaceConfirmationWindow(timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(Workspaces.CONFIRMATION_WINDOW, timeout); + } + + async clickToDeleteConfirmationCheckbox(timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(Workspaces.DELETE_CONFIRMATION_CHECKBOX, timeout); + } + + async waitAndClickEnabledConfirmationWindowDeleteButton( + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(Workspaces.DELETE_WORKSPACE_BUTTON_ENABLED, timeout); + } + + async deleteWorkspaceByActionsButton( + workspaceName: string, + timeout: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT + ): Promise { + Logger.debug(); + + 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(); + + 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(`"${workspaceName}"`); + + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + + await this.driverHelper.waitDisappearance(this.getWorkspaceListItemLocator(workspaceName), attempts, polling); + } + + async getAllCreatedWorkspacesNames(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + const workspaceNames: string[] = []; + try { + const workspaceItems: WebElement[] = await this.driverHelper.waitAllPresence( + Workspaces.WORKSPACE_ITEM_TABLE_NAME_SECTION, + timeout + ); + for (const item of workspaceItems) { + Logger.debug(`try to get ${workspaceItems.indexOf(item)} items name`); + workspaceNames.push(await item.getText()); + Logger.debug(`workspace name is "${workspaceNames[workspaceNames.length - 1]}"`); + } + } catch (e) { + Logger.debug(`${e}`); + } + + Logger.debug(`${workspaceNames.length} workspaces have been created in DevSpaces`); + return workspaceNames; + } + + async getLearnMoreDocumentationLink(): Promise { + Logger.debug(); + +<<<<<<< HEAD + 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); +======= + return await this.driverHelper.waitAndGetElementAttribute(Workspaces.LEARN_MORE_DOC_LINK, 'href'); + } + + private getWorkspaceListItemLocator(workspaceName: string): By { + return By.xpath(`//tr[td//a[text()='${workspaceName}']]`); + } +>>>>>>> main + + private getWorkspaceStatusLocator(workspaceName: string, workspaceStatus: WorkspaceStatusUI): By { + return By.xpath( + `${ + this.getWorkspaceListItemLocator(workspaceName).value + }//span[@data-testid='workspace-status-indicator' and @aria-label='${workspaceStatus}']` + ); + } + + private getActionsLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}/td/div/button[@aria-label='Actions']`); + } + + private getExpandedActionsLocator(workspaceName: string): By { + return By.xpath( + `${this.getWorkspaceListItemLocator(workspaceName).value}//button[@aria-label='Actions' and @aria-expanded='true']` + ); + } + + private getActionsPopupButtonLocator(workspaceName: string, buttonText: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}//button[text()='${buttonText}']`); + } + + private getOpenButtonLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}//td[@data-key=5]//a[text()='Open']`); + } + + private getOpenWorkspaceDetailsLinkLocator(workspaceName: string): By { + return By.xpath(`${this.getWorkspaceListItemLocator(workspaceName).value}//a[text()='${workspaceName}']`); + } +} diff --git a/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts b/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts index 07d5d7c9de4..27074835572 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 @@ -8,145 +8,171 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ import { DriverHelper } from '../../../utils/DriverHelper'; -import { injectable, inject } from 'inversify'; +import { inject, injectable } from 'inversify'; import { CLASSES, TYPES } from '../../../configs/inversify.types'; 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: By = By.css('#run-workspace-button[che-button-title="Run"]'); + private static readonly OPEN_BUTTON: By = By.css('#open-in-ide-button[che-button-title="Open"]'); + private static readonly SAVE_BUTTON: By = By.css('button[name="save-button"]'); + private static readonly ENABLED_SAVE_BUTTON: By = By.css('button[name="save-button"][aria-disabled="false"]'); + private static readonly WORKSPACE_DETAILS_LOADER: By = By.css('workspace-details-overview md-progress-linear'); + private static readonly STORAGE_TYPE_INFO_BUTTON: By = By.xpath('//label[@for="storage-type"]//following-sibling::button'); + private static readonly CLOSE_STORAGE_TYPE_INFO_BUTTON: By = By.xpath('//button[@aria-label="Close"]'); + private static readonly STORAGE_TYPE_DOC_LINK: By = By.xpath('//div/p/a'); + private static readonly DEVFILE_DOC_LINK: By = By.xpath('//a[text()="Devfile Documentation"]'); - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, - @inject(TYPES.WorkspaceUtil) private readonly testWorkspaceUtil: ITestWorkspaceUtil, - @inject(CLASSES.ProjectAndFileTests) private readonly testProjectAndFileCheCode: ProjectAndFileTests) { } + 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 = TimeoutConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING): Promise { - Logger.debug('WorkspaceDetails.waitLoaderDisappearance'); + 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); - } + await this.driverHelper.waitDisappearance(WorkspaceDetails.WORKSPACE_DETAILS_LOADER, attempts, polling); + } - async saveChanges(): Promise { - Logger.debug('WorkspaceDetails.saveChanges'); + async saveChanges(): Promise { + Logger.debug(); - await this.waitSaveButton(); - await this.clickOnSaveButton(); - await this.waitSaveButtonDisappearance(); - } + await this.waitSaveButton(); + await this.clickOnSaveButton(); + await this.waitSaveButtonDisappearance(); + } - async waitPage(workspaceName: string, timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug(`WorkspaceDetails.saveChanges workspace: "${workspaceName}"`); + 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); - } + 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(`WorkspaceDetails.waitWorkspaceTitle title: "${workspaceName}"`); + async waitWorkspaceTitle(workspaceName: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(`title: "${workspaceName}"`); - const workspaceTitleLocator: By = By.css(this.getWorkspaceTitleCssLocator(workspaceName)); + const workspaceTitleLocator: By = this.getWorkspaceTitleLocator(workspaceName); - await this.driverHelper.waitVisibility(workspaceTitleLocator, timeout); - } + await this.driverHelper.waitVisibility(workspaceTitleLocator, timeout); + } - async waitRunButton(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug('WorkspaceDetails.waitRunButton'); + async waitRunButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); - await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.RUN_BUTTON_CSS), timeout); - } + await this.driverHelper.waitVisibility(WorkspaceDetails.RUN_BUTTON, timeout); + } - async clickOnRunButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - Logger.debug('WorkspaceDetails.clickOnRunButton'); + async clickOnRunButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); - await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.RUN_BUTTON_CSS), timeout); - } + await this.driverHelper.waitAndClick(WorkspaceDetails.RUN_BUTTON, timeout); + } - async waitOpenButton(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug('WorkspaceDetails.waitOpenButton'); + async waitOpenButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); - await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.OPEN_BUTTON_CSS), timeout); - } + await this.driverHelper.waitVisibility(WorkspaceDetails.OPEN_BUTTON, timeout); + } - async openWorkspace(namespace: string, workspaceName: string, timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise { - Logger.debug(`WorkspaceDetails.openWorkspace "${namespace}/${workspaceName}"`); + 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); - } + await this.clickOnOpenButton(timeout); + await this.testProjectAndFileCheCode.waitWorkspaceReadinessForCheCodeEditor(); + await this.testWorkspaceUtil.waitWorkspaceStatus(workspaceName, WorkspaceStatus.STARTING); + } - async waitTabsPresence(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug('WorkspaceDetails.waitTabsPresence'); + async waitTabsPresence(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); - const workspaceDetailsTabs: Array = ['Overview', 'Projects', 'Containers', 'Servers', - 'Env Variables', 'Volumes', 'Config', 'SSH', 'Plugins', 'Editors']; + const workspaceDetailsTabs: Array = ['Overview', 'Devfile', 'DevWorkspace', 'Logs', 'Events']; - for (const tabTitle of workspaceDetailsTabs) { - const workspaceDetailsTabLocator: By = By.xpath(this.getTabXpathLocator(tabTitle)); + for (const tabTitle of workspaceDetailsTabs) { + const workspaceDetailsTabLocator: By = this.getTabLocator(tabTitle); - await this.driverHelper.waitVisibility(workspaceDetailsTabLocator, timeout); - } - } + await this.driverHelper.waitVisibility(workspaceDetailsTabLocator, timeout); + } + } - async selectTab(tabTitle: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - Logger.debug(`WorkspaceDetails.selectTab ${tabTitle}`); + async selectTab(tabTitle: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(`${tabTitle}`); - await this.clickOnTab(tabTitle, timeout); - await this.waitTabSelected(tabTitle, timeout); - } + await this.clickOnTab(tabTitle, timeout); + } - private getWorkspaceTitleCssLocator(workspaceName: string): string { - return `che-row-toolbar[che-title='${workspaceName}']`; - } + async clickStorageTypeInfo(): Promise { + Logger.debug(); - private getTabXpathLocator(tabTitle: string): string { - return `//md-tabs-canvas//md-tab-item//span[text()='${tabTitle}']`; - } + await this.driverHelper.waitAndClick(WorkspaceDetails.STORAGE_TYPE_INFO_BUTTON); + } - private getSelectedTabXpathLocator(tabTitle: string): string { - return `//md-tabs-canvas[@role='tablist']//md-tab-item[@aria-selected='true']//span[text()='${tabTitle}']`; - } + async getOpenStorageTypeDocumentationLink(): Promise { + Logger.debug(); - private async waitSaveButton(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - await this.driverHelper.waitVisibility(By.css(WorkspaceDetails.ENABLED_SAVE_BUTTON_CSS), timeout); - } + return await this.driverHelper.waitAndGetElementAttribute(WorkspaceDetails.STORAGE_TYPE_DOC_LINK, 'href'); + } - 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); - } + async closeStorageTypeInfo(): Promise { + Logger.debug(); - private async clickOnSaveButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.ENABLED_SAVE_BUTTON_CSS), timeout); - } + await this.driverHelper.waitAndClick(WorkspaceDetails.CLOSE_STORAGE_TYPE_INFO_BUTTON); + } - private async clickOnOpenButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - await this.driverHelper.waitAndClick(By.css(WorkspaceDetails.OPEN_BUTTON_CSS), timeout); - } + async getDevfileDocumentationLink(): Promise { + return await this.driverHelper.waitAndGetElementAttribute(WorkspaceDetails.DEVFILE_DOC_LINK, 'href'); + } - private async clickOnTab(tabTitle: string, timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { - const workspaceDetailsTabLocator: By = By.xpath(this.getTabXpathLocator(tabTitle)); + private getWorkspaceTitleLocator(workspaceName: string): By { + return By.xpath(`//h1[text()='${workspaceName}']`); + } + private getTabLocator(tabTitle: string): By { + return By.xpath(`//button[contains(@id,'${tabTitle}')]`); + } - await this.driverHelper.waitAndClick(workspaceDetailsTabLocator, timeout); - } + private async waitSaveButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + await this.driverHelper.waitVisibility(WorkspaceDetails.ENABLED_SAVE_BUTTON, timeout); + } - private async waitTabSelected(tabTitle: string, timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { - const selectedTabLocator: By = By.xpath(this.getSelectedTabXpathLocator(tabTitle)); + private async waitSaveButtonDisappearance( + attempts: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, + polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING + ): Promise { + await this.driverHelper.waitDisappearance(WorkspaceDetails.SAVE_BUTTON, attempts, polling); + } - await this.driverHelper.waitVisibility(selectedTabLocator, timeout); - } + private async clickOnSaveButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + await this.driverHelper.waitAndClick(WorkspaceDetails.ENABLED_SAVE_BUTTON, timeout); + } + private async clickOnOpenButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + await this.driverHelper.waitAndClick(WorkspaceDetails.OPEN_BUTTON, timeout); + } + + private async clickOnTab(tabTitle: string, timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + const workspaceDetailsTabLocator: By = this.getTabLocator(tabTitle); + await this.driverHelper.waitAndClick(workspaceDetailsTabLocator, timeout); + } } diff --git a/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts.orig b/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts.orig new file mode 100644 index 00000000000..c6fe26bd4c5 --- /dev/null +++ b/tests/e2e/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts.orig @@ -0,0 +1,189 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { DriverHelper } from '../../../utils/DriverHelper'; +import { inject, injectable } from 'inversify'; +import { CLASSES, TYPES } from '../../../configs/inversify.types'; +import 'reflect-metadata'; +import { By } from 'selenium-webdriver'; +import { WorkspaceStatus } from '../../../utils/workspace/WorkspaceStatus'; +import { Logger } from '../../../utils/Logger'; +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: By = By.css('#run-workspace-button[che-button-title="Run"]'); + private static readonly OPEN_BUTTON: By = By.css('#open-in-ide-button[che-button-title="Open"]'); + private static readonly SAVE_BUTTON: By = By.css('button[name="save-button"]'); + private static readonly ENABLED_SAVE_BUTTON: By = By.css('button[name="save-button"][aria-disabled="false"]'); + private static readonly WORKSPACE_DETAILS_LOADER: By = By.css('workspace-details-overview md-progress-linear'); + private static readonly STORAGE_TYPE_INFO_BUTTON: By = By.xpath('//label[@for="storage-type"]//following-sibling::button'); + private static readonly CLOSE_STORAGE_TYPE_INFO_BUTTON: By = By.xpath('//button[@aria-label="Close"]'); + private static readonly STORAGE_TYPE_DOC_LINK: By = By.xpath('//div/p/a'); + private static readonly DEVFILE_DOC_LINK: By = By.xpath('//a[text()="Devfile Documentation"]'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper, + @inject(TYPES.WorkspaceUtil) + private readonly testWorkspaceUtil: ITestWorkspaceUtil, + @inject(CLASSES.ProjectAndFileTests) + private readonly testProjectAndFileCheCode: ProjectAndFileTests + ) {} + +<<<<<<< HEAD + async waitLoaderDisappearance(attempts: number = TimeoutConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING): Promise { + Logger.debug('WorkspaceDetails.waitLoaderDisappearance'); +======= + async waitLoaderDisappearance( + attempts: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, + polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING + ): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.waitDisappearance(WorkspaceDetails.WORKSPACE_DETAILS_LOADER, 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 = this.getWorkspaceTitleLocator(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(WorkspaceDetails.RUN_BUTTON, timeout); + } + + async clickOnRunButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(WorkspaceDetails.RUN_BUTTON, timeout); + } + + async waitOpenButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(WorkspaceDetails.OPEN_BUTTON, 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(workspaceName, WorkspaceStatus.STARTING); + } + + async waitTabsPresence(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(); + + const workspaceDetailsTabs: Array = ['Overview', 'Devfile', 'DevWorkspace', 'Logs', 'Events']; + + for (const tabTitle of workspaceDetailsTabs) { + const workspaceDetailsTabLocator: By = this.getTabLocator(tabTitle); + + await this.driverHelper.waitVisibility(workspaceDetailsTabLocator, timeout); + } + } + + async selectTab(tabTitle: string, timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + Logger.debug(`${tabTitle}`); + + await this.clickOnTab(tabTitle, timeout); + } + + async clickStorageTypeInfo(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(WorkspaceDetails.STORAGE_TYPE_INFO_BUTTON); + } + + async getOpenStorageTypeDocumentationLink(): Promise { + Logger.debug(); + + return await this.driverHelper.waitAndGetElementAttribute(WorkspaceDetails.STORAGE_TYPE_DOC_LINK, 'href'); + } + +<<<<<<< HEAD + 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); + } +======= + async closeStorageTypeInfo(): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.waitAndClick(WorkspaceDetails.CLOSE_STORAGE_TYPE_INFO_BUTTON); + } + + async getDevfileDocumentationLink(): Promise { + return await this.driverHelper.waitAndGetElementAttribute(WorkspaceDetails.DEVFILE_DOC_LINK, 'href'); + } + + private getWorkspaceTitleLocator(workspaceName: string): By { + return By.xpath(`//h1[text()='${workspaceName}']`); + } + + private getTabLocator(tabTitle: string): By { + return By.xpath(`//button[contains(@id,'${tabTitle}')]`); + } + + private async waitSaveButton(timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise { + await this.driverHelper.waitVisibility(WorkspaceDetails.ENABLED_SAVE_BUTTON, timeout); + } + + private async waitSaveButtonDisappearance( + attempts: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_ATTEMPTS, + polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING + ): Promise { + await this.driverHelper.waitDisappearance(WorkspaceDetails.SAVE_BUTTON, attempts, polling); + } + + private async clickOnSaveButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + await this.driverHelper.waitAndClick(WorkspaceDetails.ENABLED_SAVE_BUTTON, timeout); + } + + private async clickOnOpenButton(timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + await this.driverHelper.waitAndClick(WorkspaceDetails.OPEN_BUTTON, timeout); + } + + private async clickOnTab(tabTitle: string, timeout: number = TIMEOUT_CONSTANTS.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise { + const workspaceDetailsTabLocator: By = this.getTabLocator(tabTitle); + await this.driverHelper.waitAndClick(workspaceDetailsTabLocator, timeout); + } +} diff --git a/tests/e2e/pageobjects/git-providers/OauthPage.ts b/tests/e2e/pageobjects/git-providers/OauthPage.ts index 3e8de404251..62a05f96d68 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,203 @@ 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: { - 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} or ${GitProviderType.BITBUCKET}`); - } - } - } - - async waitLoginPage(): Promise { - Logger.debug('OauthPage.waitLoginPage'); - - await this.driverHelper.waitVisibility(OauthPage.LOGIN_FORM, TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM * 3); - } - - async enterUserName(userName: string): Promise { - Logger.debug(`this.enterUserName "${userName}"`); - - await this.driverHelper.enterValue(OauthPage.LOGIN_FORM, userName); - } - - async enterPassword(password: string): Promise { - Logger.debug(`OauthPage.enterPassword`); - - await this.driverHelper.enterValue(OauthPage.PASSWORD_FORM, password); - } - - async clickOnSubmitButton(): Promise { - Logger.debug('OauthPage.clickOnLoginButton'); - - await this.driverHelper.waitAndClick(OauthPage.SUBMIT_BUTTON); - } - - async clickOnNotRememberCredentialsButton(): Promise { - Logger.debug('OauthPage.clickOnNotRememberCredentialsButton'); - - await this.driverHelper.waitAndClick(OauthPage.DENY_SAVE_CREDENTIALS_BUTTON); - } - - async waitClosingLoginPage(): Promise { - Logger.debug('OauthPage.waitClosingLoginPage'); - - await this.driverHelper.waitDisappearance(OauthPage.PASSWORD_FORM); - } - - async waitOauthPage(): Promise { - Logger.debug('OauthPage.waitOauthPage'); - - await this.driverHelper.waitVisibility(OauthPage.APPROVE_BUTTON); - } - - async clickOnApproveButton(): Promise { - Logger.debug('OauthPage.clickOnApproveButton'); - - await this.driverHelper.waitAndClick(OauthPage.APPROVE_BUTTON); - } - - async clickOnDenyAccessButton(): Promise { - Logger.debug('OauthPage.clickOnDenyAccessButton'); - - await this.driverHelper.waitAndClick(OauthPage.DENY_ACCESS_BUTTON); - } - - async waitDisappearanceOauthPage(): Promise { - Logger.debug('OauthPage.waitDisappearanceOauthPage'); - - await this.driverHelper.waitDisappearance(OauthPage.APPROVE_BUTTON); - } - - async login(): Promise { - Logger.debug('OauthPage.login'); - - await this.waitLoginPage(); - await this.enterUserName(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_USERNAME); - if (FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.AZURE) { - await this.clickOnSubmitButton(); - } - await this.enterPassword(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_PASSWORD); - await this.clickOnSubmitButton(); - if (FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.AZURE) { - await this.clickOnNotRememberCredentialsButton(); - } - await this.waitClosingLoginPage(); - } - - async confirmAccess(): Promise { - Logger.debug('OauthPage.confirmAccess'); - - try { - await this.clickOnApproveButton(); - await this.waitDisappearanceOauthPage(); - } catch (e) { - Logger.debug('OauthPage.confirmAccess - access was not confirmed, retrying to click conformation button'); - // workaround for github, azure oauth conformation 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('OauthPage.denyAccess'); - - try { - await this.clickOnDenyAccessButton(); - await this.waitDisappearanceOauthPage(); - } catch (e) { - Logger.debug('OauthPage.denyAccess - deny access was not confirmed, retrying to click conformation button'); - // workaround for github, azure oauth conformation 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_SERVER_OAUTH1: + { + 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.BITBUCKET_SERVER_OAUTH2: + { + OauthPage.LOGIN_FORM = By.id('j_username'); + OauthPage.PASSWORD_FORM = By.id('j_password'); + OauthPage.APPROVE_BUTTON = By.xpath('//span[text()="Allow"]'); + OauthPage.SUBMIT_BUTTON = By.id('submit'); + OauthPage.DENY_ACCESS_BUTTON = By.xpath('//span[text()="Deny"]'); + } + break; + case GitProviderType.BITBUCKET_CLOUD_OAUTH2: + { + OauthPage.LOGIN_FORM = By.id('username'); + OauthPage.PASSWORD_FORM = By.id('password'); + OauthPage.SUBMIT_BUTTON = By.id('login-submit'); + OauthPage.APPROVE_BUTTON = By.xpath('//button[@value="approve"]'); + OauthPage.DENY_ACCESS_BUTTON = By.xpath('//button[@value="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}, ${GitProviderType.BITBUCKET_SERVER_OAUTH1}, ${GitProviderType.BITBUCKET_SERVER_OAUTH2} or ${GitProviderType.BITBUCKET_CLOUD_OAUTH2}` + ); + } + } + } + + 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 || + FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.BITBUCKET_CLOUD_OAUTH2 + ) { + 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/git-providers/OauthPage.ts.orig b/tests/e2e/pageobjects/git-providers/OauthPage.ts.orig new file mode 100644 index 00000000000..bc2d1eb6eed --- /dev/null +++ b/tests/e2e/pageobjects/git-providers/OauthPage.ts.orig @@ -0,0 +1,373 @@ +/** ******************************************************************* + * copyright (c) 2019 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { inject, injectable } from 'inversify'; +import { By } from 'selenium-webdriver'; +import { CLASSES } from '../../configs/inversify.types'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { Logger } from '../../utils/Logger'; +<<<<<<< HEAD +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { FactoryTestConstants, GitProviderType } from '../../constants/FactoryTestConstants'; +import { OAuthConstants } from '../../constants/OAuthConstants'; + +@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: { + 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} or ${GitProviderType.BITBUCKET}`); + } + } + } +======= +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 (FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER) { + case GitProviderType.BITBUCKET_SERVER_OAUTH1: + { + 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.BITBUCKET_SERVER_OAUTH2: + { + OauthPage.LOGIN_FORM = By.id('j_username'); + OauthPage.PASSWORD_FORM = By.id('j_password'); + OauthPage.APPROVE_BUTTON = By.xpath('//span[text()="Allow"]'); + OauthPage.SUBMIT_BUTTON = By.id('submit'); + OauthPage.DENY_ACCESS_BUTTON = By.xpath('//span[text()="Deny"]'); + } + break; + case GitProviderType.BITBUCKET_CLOUD_OAUTH2: + { + OauthPage.LOGIN_FORM = By.id('username'); + OauthPage.PASSWORD_FORM = By.id('password'); + OauthPage.SUBMIT_BUTTON = By.id('login-submit'); + OauthPage.APPROVE_BUTTON = By.xpath('//button[@value="approve"]'); + OauthPage.DENY_ACCESS_BUTTON = By.xpath('//button[@value="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}, ${GitProviderType.BITBUCKET_SERVER_OAUTH1}, ${GitProviderType.BITBUCKET_SERVER_OAUTH2} or ${GitProviderType.BITBUCKET_CLOUD_OAUTH2}` + ); + } + } + } +>>>>>>> main + + async waitLoginPage(): Promise { + Logger.debug(); + +<<<<<<< HEAD + await this.driverHelper.waitVisibility(OauthPage.LOGIN_FORM, TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM * 3); + } +======= + await this.driverHelper.waitVisibility(OauthPage.LOGIN_FORM, TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM * 3); + } + + async enterUserName(userName: string): Promise { + Logger.debug(`"${userName}"`); +>>>>>>> main + + await this.driverHelper.enterValue(OauthPage.LOGIN_FORM, userName); + } + +<<<<<<< HEAD + await this.driverHelper.enterValue(OauthPage.LOGIN_FORM, userName); + } +======= + async enterPassword(password: string): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.enterValue(OauthPage.PASSWORD_FORM, password); + } + +<<<<<<< HEAD + await this.driverHelper.enterValue(OauthPage.PASSWORD_FORM, password); + } + + async clickOnSubmitButton(): Promise { + Logger.debug('OauthPage.clickOnLoginButton'); + + await this.driverHelper.waitAndClick(OauthPage.SUBMIT_BUTTON); + } + + async clickOnNotRememberCredentialsButton(): Promise { + Logger.debug('OauthPage.clickOnNotRememberCredentialsButton'); + + await this.driverHelper.waitAndClick(OauthPage.DENY_SAVE_CREDENTIALS_BUTTON); + } +======= + async clickOnSubmitButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OauthPage.SUBMIT_BUTTON); + } + + async clickOnNotRememberCredentialsButton(): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.waitAndClick(OauthPage.DENY_SAVE_CREDENTIALS_BUTTON); + } + +<<<<<<< HEAD + await this.driverHelper.waitDisappearance(OauthPage.PASSWORD_FORM); + } +======= + async waitClosingLoginPage(): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.waitDisappearance(OauthPage.PASSWORD_FORM); + } + +<<<<<<< HEAD + await this.driverHelper.waitVisibility(OauthPage.APPROVE_BUTTON); + } +======= + async waitOauthPage(): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.waitVisibility(OauthPage.APPROVE_BUTTON); + } + +<<<<<<< HEAD + await this.driverHelper.waitAndClick(OauthPage.APPROVE_BUTTON); + } +======= + async clickOnApproveButton(): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.waitAndClick(OauthPage.APPROVE_BUTTON); + } + +<<<<<<< HEAD + await this.driverHelper.waitAndClick(OauthPage.DENY_ACCESS_BUTTON); + } +======= + async clickOnDenyAccessButton(): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.waitAndClick(OauthPage.DENY_ACCESS_BUTTON); + } + +<<<<<<< HEAD + await this.driverHelper.waitDisappearance(OauthPage.APPROVE_BUTTON); + } +======= + async waitDisappearanceOauthPage(): Promise { + Logger.debug(); +>>>>>>> main + + await this.driverHelper.waitDisappearance(OauthPage.APPROVE_BUTTON); + } + +<<<<<<< HEAD + await this.waitLoginPage(); + await this.enterUserName(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_USERNAME); + if (FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.AZURE) { + await this.clickOnSubmitButton(); + } + await this.enterPassword(OAuthConstants.TS_SELENIUM_GIT_PROVIDER_PASSWORD); + await this.clickOnSubmitButton(); + if (FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.AZURE) { + await this.clickOnNotRememberCredentialsButton(); + } + await this.waitClosingLoginPage(); + } +======= + async login(): Promise { + Logger.debug(); +>>>>>>> main + + 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 || + FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER === GitProviderType.BITBUCKET_CLOUD_OAUTH2 + ) { + 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(); + } + +<<<<<<< HEAD + try { + await this.clickOnApproveButton(); + await this.waitDisappearanceOauthPage(); + } catch (e) { + Logger.debug('OauthPage.confirmAccess - access was not confirmed, retrying to click conformation button'); + // workaround for github, azure oauth conformation page (bot security) + await this.driverHelper.getAction() + .move({ + origin: await this.driverHelper.waitPresence(OauthPage.APPROVE_BUTTON) + }) + .click() + .perform(); + await this.waitDisappearanceOauthPage(); + } + } +======= + async confirmAccess(): Promise { + Logger.debug(); +>>>>>>> main + + 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(); + } + } + +<<<<<<< HEAD + try { + await this.clickOnDenyAccessButton(); + await this.waitDisappearanceOauthPage(); + } catch (e) { + Logger.debug('OauthPage.denyAccess - deny access was not confirmed, retrying to click conformation button'); + // workaround for github, azure oauth conformation page (bot security) + await this.driverHelper.getAction() + .move({ + origin: await this.driverHelper.waitPresence(OauthPage.DENY_ACCESS_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(); + } + } +>>>>>>> main +} diff --git a/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts b/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts index 02601dc8951..3e5afd4c4b9 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,84 @@ 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'; +import { injectable } from 'inversify'; /** - * This class allows us to change or add some specific locators base on "monaco-page-object" and "vscode-extension-tester-locators". + * 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". */ +@injectable() 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_USE_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('//div[@class="monaco-dialog-box"]//a[@class="monaco-button monaco-text-button"]') + }, + ScmView: { + actionConstructor: (title: string): By => By.xpath(`.//a[@aria-label='${title}']`) + }, + ContextMenu: { + contextView: By.className('monaco-menu-container') + } + }, + extras: { + ExtensionsViewSection: { + requireReloadButton: By.xpath('//a[text()="Reload Required"]') + }, + TreeItem: { + projectFolderItem: By.className('pane-header expanded') + }, + ScmView: { + manageWorkspaceTrust: By.xpath('.//a[@class="monaco-button monaco-text-button"]'), + modifiedFile: By.xpath('//div[@class="monaco-list-row" and contains(@aria-label, "Modified")]') + }, + Workbench: { + workspaceTrustButton: By.xpath('//a[@role="button" and text()="Trust"]') + } + } + }; + } - 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/ide/CheCodeLocatorLoader.ts.orig b/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts.orig new file mode 100644 index 00000000000..a2e1b8e3d8e --- /dev/null +++ b/tests/e2e/pageobjects/ide/CheCodeLocatorLoader.ts.orig @@ -0,0 +1,106 @@ +/** ******************************************************************* + * copyright (c) 2019 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { LocatorLoader } from 'monaco-page-objects/out/locators/loader'; +import { getLocatorsPath } from 'vscode-extension-tester-locators'; +import { LocatorDiff, Locators } from 'monaco-page-objects'; +import { By } from 'selenium-webdriver'; +import clone from 'clone-deep'; +<<<<<<< HEAD +import { MonacoConstants } from '../../constants/MonacoConstants'; +======= +import { MONACO_CONSTANTS } from '../../constants/MONACO_CONSTANTS'; +import { injectable } from 'inversify'; +>>>>>>> main + +/** + * 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". + */ + +@injectable() +export class CheCodeLocatorLoader extends LocatorLoader { + readonly webCheCodeLocators: Locators; + +<<<<<<< HEAD + 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_USE_VERSION, + MONACO_CONSTANTS.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION, + getLocatorsPath() + ); + this.webCheCodeLocators = this.mergeLocators(); + } +>>>>>>> main + + private webLocatorDiff(): LocatorDiff { + return { + locators: { + WelcomeContent: { + text: By.xpath('//*[@class="dialog-message-text" and contains(text(), "trust")]'), + button: By.xpath('//div[@class="monaco-dialog-box"]//a[@class="monaco-button monaco-text-button"]') + }, + ScmView: { + actionConstructor: (title: string): By => By.xpath(`.//a[@aria-label='${title}']`) + }, + ContextMenu: { + contextView: By.className('monaco-menu-container') + } + }, + extras: { + ExtensionsViewSection: { + requireReloadButton: By.xpath('//a[text()="Reload Required"]') + }, + TreeItem: { + projectFolderItem: By.className('pane-header expanded') + }, + ScmView: { + manageWorkspaceTrust: By.xpath('.//a[@class="monaco-button monaco-text-button"]'), + modifiedFile: By.xpath('//div[@class="monaco-list-row" and contains(@aria-label, "Modified")]') + }, + Workbench: { + workspaceTrustButton: By.xpath('//a[@role="button" and text()="Trust"]') + } + } + }; + } + + private merge(target: any, obj: any): object { + for (const key in obj) { + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } + + 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; + } + + private mergeLocators(): Locators { + const target: Locators = super.loadLocators(); + + this.merge(target, this.webLocatorDiff().locators as Locators); + this.merge(target, this.webLocatorDiff().extras as Locators); + + return target; + } +} diff --git a/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts b/tests/e2e/pageobjects/login/interfaces/ICheLoginPage.ts index 0bb798caf31..5a792c1297b 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(user?: string, password?: string): Promise; } diff --git a/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts b/tests/e2e/pageobjects/login/interfaces/IOcpLoginPage.ts index 44c54a4c86b..4d09dc10d28 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(): Promise; } diff --git a/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts b/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts index 6554441655b..b2c189a8e7c 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 @@ -8,51 +8,52 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ import 'reflect-metadata'; -import { injectable, inject } from 'inversify'; +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 DEX_PAGE_CONTENT_CONTAINER: By = By.className('dex-container'); + private static readonly LOGIN_INPUT: By = By.id('login'); + private static readonly PASSWORD_INPUT: By = By.id('password'); + private static readonly SUBMIT_BUTTON: By = By.id('submit-login'); - 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(`${this.constructor.name}.${this.waitDexLoginPage.name}`); + await this.driverHelper.waitVisibility(DexLoginPage.DEX_PAGE_CONTENT_CONTAINER, 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(`${this.constructor.name}.${this.clickOnLoginButton.name}`); + await this.driverHelper.waitAndClick(DexLoginPage.SUBMIT_BUTTON); + } - await this.driverHelper.waitAndClick(DexLoginPage.submitButton); - } + async enterUserNameKubernetes(userName: string): Promise { + Logger.debug(); - async enterUserNameKubernetes(userName: string): Promise { - Logger.debug(`${this.constructor.name}.${this.enterUserNameKubernetes.name}`); + await this.driverHelper.enterValue(DexLoginPage.LOGIN_INPUT, userName); + } - await this.driverHelper.enterValue(DexLoginPage.loginInput, userName); - } + async enterPasswordKubernetes(password: string): Promise { + Logger.debug(); - async enterPasswordKubernetes(password: string): Promise { - Logger.debug(`${this.constructor.name}.${this.enterPasswordKubernetes.name}`); + await this.driverHelper.enterValue(DexLoginPage.PASSWORD_INPUT, password); + } - await this.driverHelper.enterValue(DexLoginPage.passwordInput, password); - } + async waitDexLoginPageDisappearance(): Promise { + Logger.debug(); - async waitDexLoginPageDisappearance(): Promise { - Logger.debug(`${this.constructor.name}.${this.waitDexLoginPageDisappearance.name}`); - - await this.driverHelper.waitDisappearance(DexLoginPage.dexPageContentContainer, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + await this.driverHelper.waitDisappearance(DexLoginPage.DEX_PAGE_CONTENT_CONTAINER, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } } diff --git a/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts.orig b/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts.orig new file mode 100644 index 00000000000..690f5c4ca80 --- /dev/null +++ b/tests/e2e/pageobjects/login/kubernetes/DexLoginPage.ts.orig @@ -0,0 +1,113 @@ +<<<<<<< HEAD +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. +======= +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. +>>>>>>> main + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +<<<<<<< HEAD +import { injectable, inject } from 'inversify'; +import { CLASSES } from '../../../configs/inversify.types'; +import { Logger } from '../../../utils/Logger'; +import { By } from 'selenium-webdriver'; +import { TimeoutConstants } from '../../../constants/TimeoutConstants'; +======= +import { inject, injectable } from 'inversify'; +import { CLASSES } from '../../../configs/inversify.types'; +import { Logger } from '../../../utils/Logger'; +import { By } from 'selenium-webdriver'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; +>>>>>>> main +import { DriverHelper } from '../../../utils/DriverHelper'; + +@injectable() +export class DexLoginPage { +<<<<<<< HEAD + + 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) { } + + async waitDexLoginPage(): Promise { + Logger.debug(`${this.constructor.name}.${this.waitDexLoginPage.name}`); + + await this.driverHelper.waitVisibility(DexLoginPage.dexPageContentContainer, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + async clickOnLoginButton(): Promise { + Logger.debug(`${this.constructor.name}.${this.clickOnLoginButton.name}`); + + await this.driverHelper.waitAndClick(DexLoginPage.submitButton); + } + + async enterUserNameKubernetes(userName: string): Promise { + Logger.debug(`${this.constructor.name}.${this.enterUserNameKubernetes.name}`); + + await this.driverHelper.enterValue(DexLoginPage.loginInput, userName); + } + + async enterPasswordKubernetes(password: string): Promise { + Logger.debug(`${this.constructor.name}.${this.enterPasswordKubernetes.name}`); + + await this.driverHelper.enterValue(DexLoginPage.passwordInput, password); + } + + async waitDexLoginPageDisappearance(): Promise { + Logger.debug(`${this.constructor.name}.${this.waitDexLoginPageDisappearance.name}`); + + await this.driverHelper.waitDisappearance(DexLoginPage.dexPageContentContainer, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } +======= + private static readonly DEX_PAGE_CONTENT_CONTAINER: By = By.className('dex-container'); + private static readonly LOGIN_INPUT: By = By.id('login'); + private static readonly PASSWORD_INPUT: By = By.id('password'); + private static readonly SUBMIT_BUTTON: By = By.id('submit-login'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async waitDexLoginPage(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(DexLoginPage.DEX_PAGE_CONTENT_CONTAINER, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + async clickOnLoginButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(DexLoginPage.SUBMIT_BUTTON); + } + + async enterUserNameKubernetes(userName: string): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(DexLoginPage.LOGIN_INPUT, userName); + } + + async enterPasswordKubernetes(password: string): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(DexLoginPage.PASSWORD_INPUT, password); + } + + async waitDexLoginPageDisappearance(): Promise { + Logger.debug(); + + await this.driverHelper.waitDisappearance(DexLoginPage.DEX_PAGE_CONTENT_CONTAINER, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } +>>>>>>> main +} diff --git a/tests/e2e/pageobjects/login/kubernetes/KubernetesLoginPage.ts b/tests/e2e/pageobjects/login/kubernetes/KubernetesLoginPage.ts index 3390b462fc1..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 @@ -8,26 +8,27 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ import 'reflect-metadata'; -import { injectable, inject } from 'inversify'; +import { inject, injectable } from 'inversify'; 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(`${this.constructor.name}.${this.login.name}`); - - 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/kubernetes/KubernetesLoginPage.ts.orig b/tests/e2e/pageobjects/login/kubernetes/KubernetesLoginPage.ts.orig new file mode 100644 index 00000000000..cc700c26d59 --- /dev/null +++ b/tests/e2e/pageobjects/login/kubernetes/KubernetesLoginPage.ts.orig @@ -0,0 +1,63 @@ +<<<<<<< HEAD +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. +======= +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. +>>>>>>> main + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +<<<<<<< HEAD +import { injectable, inject } from 'inversify'; +======= +import { inject, injectable } from 'inversify'; +>>>>>>> main +import { CLASSES } from '../../../configs/inversify.types'; +import { Logger } from '../../../utils/Logger'; +import { ICheLoginPage } from '../interfaces/ICheLoginPage'; +import { DexLoginPage } from './DexLoginPage'; +<<<<<<< HEAD +import { OAuthConstants } from '../../../constants/OAuthConstants'; + +@injectable() +export class KubernetesLoginPage implements ICheLoginPage { + + constructor( + @inject(CLASSES.DexLoginPage) private readonly dexLoginPage: DexLoginPage) { } + + async login(): Promise { + Logger.debug(`${this.constructor.name}.${this.login.name}`); + + 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(); + } +======= +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; + +@injectable() +export class KubernetesLoginPage implements ICheLoginPage { + constructor( + @inject(CLASSES.DexLoginPage) + private readonly dexLoginPage: DexLoginPage + ) {} + + async login(): Promise { + Logger.debug(); + + 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(); + } +>>>>>>> main +} diff --git a/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts b/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts index 4101ee0966b..f3e7fa5cff2 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 @@ -8,85 +8,80 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ import 'reflect-metadata'; -import { injectable, inject } from 'inversify'; +import { inject, injectable } from 'inversify'; import { DriverHelper } from '../../../utils/DriverHelper'; import { CLASSES } from '../../../configs/inversify.types'; import { By } from 'selenium-webdriver'; import { Logger } from '../../../utils/Logger'; -import { TimeoutConstants } from '../../../constants/TimeoutConstants'; -import { 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_WELCOME_MESSAGE: By = By.xpath('//*[contains(text(), "Welcome")]'); + private static readonly LOGIN_BUTTON: By = By.css('button[type=submit]'); + private static readonly LOGIN_PROVIDER_BUTTON: By = By.xpath(`//a[text()="${OAUTH_CONSTANTS.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}"]`); + private static readonly AUTHORIZE_OPENSHIFT_ACCESS_HEADER: By = By.xpath('//h1[text()="Authorize Access"]'); + private static readonly APPROVE_ACCESS_BUTTON: By = By.css('input[name="approve"]'); + private static readonly USERNAME_INPUT: By = By.id('inputUsername'); + private static readonly PASSWORD_INPUT: By = By.id('inputPassword'); - 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('OcpLoginPage.waitOpenShiftLoginWelcomePage'); + await this.driverHelper.waitVisibility(OcpLoginPage.LOGIN_PAGE_WELCOME_MESSAGE, 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 waitAndClickOnLoginProviderTitle(): Promise { + Logger.debug(); - async clickOnLoginProviderTitle(): Promise { - Logger.debug('OcpLoginPage.clickOnLoginProviderTitle'); + await this.driverHelper.waitAndClick(OcpLoginPage.LOGIN_PROVIDER_BUTTON, 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('OcpLoginPage.isIdentityProviderLinkVisible'); + return await this.driverHelper.waitVisibilityBoolean(OcpLoginPage.LOGIN_PROVIDER_BUTTON, 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('OcpLoginPage.isAuthorizeOpenShiftIdentityProviderPageVisible'); + return await this.driverHelper.isVisible(OcpLoginPage.AUTHORIZE_OPENSHIFT_ACCESS_HEADER); + } - const authorizeOpenshiftIdentityProviderPageLocator: By = By.xpath('//h1[text()=\'Authorize Access\']'); - return await this.driverHelper.isVisible(authorizeOpenshiftIdentityProviderPageLocator); - } + async clickOnApproveAuthorizeAccessButton(): Promise { + Logger.debug(); - async waitAuthorizeOpenShiftIdentityProviderPage(): Promise { - Logger.debug('OcpLoginPage.waitAuthorizeOpenShiftIdentityProviderPage'); + await this.driverHelper.waitAndClick(OcpLoginPage.APPROVE_ACCESS_BUTTON); + } - const authorizeOpenshiftIdentityProviderPageLocator: By = By.xpath('//h1[text()=\'Authorize Access\']'); - await this.driverHelper.waitVisibility(authorizeOpenshiftIdentityProviderPageLocator, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + async enterUserNameOpenShift(userName: string): Promise { + Logger.debug(`"${userName}"`); - async clickOnApproveAuthorizeAccessButton(): Promise { - Logger.debug('OcpLoginPage.clickOnApproveAuthorizeAccessOpenshift'); + await this.driverHelper.enterValue(OcpLoginPage.USERNAME_INPUT, userName); + } - const approveAuthorizeAccessOcpLocator: By = By.css('input[name=\'approve\']'); - await this.driverHelper.waitAndClick(approveAuthorizeAccessOcpLocator); - } + async enterPasswordOpenShift(userPassword: string): Promise { + Logger.debug(); - async enterUserNameOpenShift(userName: string): Promise { - Logger.debug(`OcpLoginPage.enterUserNameOpenShift "${userName}"`); + await this.driverHelper.enterValue(OcpLoginPage.PASSWORD_INPUT, userPassword); + } - await this.driverHelper.enterValue(By.id('inputUsername'), userName); - } + async clickOnLoginButton(): Promise { + Logger.debug(); - async enterPasswordOpenShift(passw: string): Promise { - Logger.debug(`OcpLoginPage.enterPasswordOpenShift"`); + await this.driverHelper.waitAndClick(OcpLoginPage.LOGIN_BUTTON); + } - await this.driverHelper.enterValue(By.id('inputPassword'), passw); - } + async waitDisappearanceOpenShiftLoginWelcomePage(): Promise { + Logger.debug(); - async clickOnLoginButton(): Promise { - Logger.debug('OcpLoginPage.clickOnLoginButton'); - - const loginButtonLocator: By = By.css('button[type=submit]'); - await this.driverHelper.waitAndClick(loginButtonLocator); - } - - async waitDisappearanceOpenShiftLoginWelcomePage(): Promise { - Logger.debug('OcpLoginPage.waitDisappearanceOpenShiftLoginWelcomePage'); - - await this.driverHelper.waitDisappearance(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH)); - } + await this.driverHelper.waitDisappearance(OcpLoginPage.LOGIN_PAGE_WELCOME_MESSAGE); + } } diff --git a/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts.orig b/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts.orig new file mode 100644 index 00000000000..33f33be8250 --- /dev/null +++ b/tests/e2e/pageobjects/login/openshift/OcpLoginPage.ts.orig @@ -0,0 +1,175 @@ +<<<<<<< HEAD +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. +======= +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. +>>>>>>> main + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +<<<<<<< HEAD +import { injectable, inject } from 'inversify'; +======= +import { inject, injectable } from 'inversify'; +>>>>>>> main +import { DriverHelper } from '../../../utils/DriverHelper'; +import { CLASSES } from '../../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { Logger } from '../../../utils/Logger'; +<<<<<<< HEAD +import { TimeoutConstants } from '../../../constants/TimeoutConstants'; +import { OAuthConstants } from '../../../constants/OAuthConstants'; + +@injectable() +export class OcpLoginPage { + + private static readonly LOGIN_PAGE_OPENSHIFT_XPATH: string = '//*[contains(text(), \'Welcome\')]'; + + constructor( + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + + async waitOpenShiftLoginWelcomePage(): Promise { + Logger.debug('OcpLoginPage.waitOpenShiftLoginWelcomePage'); + + await this.driverHelper.waitVisibility(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH), TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + async clickOnLoginProviderTitle(): Promise { + Logger.debug('OcpLoginPage.clickOnLoginProviderTitle'); + + 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('OcpLoginPage.isIdentityProviderLinkVisible'); + + 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('OcpLoginPage.isAuthorizeOpenShiftIdentityProviderPageVisible'); + + const authorizeOpenshiftIdentityProviderPageLocator: By = By.xpath('//h1[text()=\'Authorize Access\']'); + return await this.driverHelper.isVisible(authorizeOpenshiftIdentityProviderPageLocator); + } + + async waitAuthorizeOpenShiftIdentityProviderPage(): Promise { + Logger.debug('OcpLoginPage.waitAuthorizeOpenShiftIdentityProviderPage'); + + 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('OcpLoginPage.clickOnApproveAuthorizeAccessOpenshift'); + + const approveAuthorizeAccessOcpLocator: By = By.css('input[name=\'approve\']'); + await this.driverHelper.waitAndClick(approveAuthorizeAccessOcpLocator); + } + + async enterUserNameOpenShift(userName: string): Promise { + Logger.debug(`OcpLoginPage.enterUserNameOpenShift "${userName}"`); + + await this.driverHelper.enterValue(By.id('inputUsername'), userName); + } + + async enterPasswordOpenShift(passw: string): Promise { + Logger.debug(`OcpLoginPage.enterPasswordOpenShift"`); + + await this.driverHelper.enterValue(By.id('inputPassword'), passw); + } + + async clickOnLoginButton(): Promise { + Logger.debug('OcpLoginPage.clickOnLoginButton'); + + const loginButtonLocator: By = By.css('button[type=submit]'); + await this.driverHelper.waitAndClick(loginButtonLocator); + } + + async waitDisappearanceOpenShiftLoginWelcomePage(): Promise { + Logger.debug('OcpLoginPage.waitDisappearanceOpenShiftLoginWelcomePage'); + + await this.driverHelper.waitDisappearance(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH)); + } +======= +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; + +@injectable() +export class OcpLoginPage { + private static readonly LOGIN_PAGE_WELCOME_MESSAGE: By = By.xpath('//*[contains(text(), "Welcome")]'); + private static readonly LOGIN_BUTTON: By = By.css('button[type=submit]'); + private static readonly LOGIN_PROVIDER_BUTTON: By = By.xpath(`//a[text()="${OAUTH_CONSTANTS.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}"]`); + private static readonly AUTHORIZE_OPENSHIFT_ACCESS_HEADER: By = By.xpath('//h1[text()="Authorize Access"]'); + private static readonly APPROVE_ACCESS_BUTTON: By = By.css('input[name="approve"]'); + private static readonly USERNAME_INPUT: By = By.id('inputUsername'); + private static readonly PASSWORD_INPUT: By = By.id('inputPassword'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async waitOpenShiftLoginWelcomePage(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(OcpLoginPage.LOGIN_PAGE_WELCOME_MESSAGE, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + async waitAndClickOnLoginProviderTitle(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OcpLoginPage.LOGIN_PROVIDER_BUTTON, TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL); + } + + async isIdentityProviderLinkVisible(): Promise { + Logger.debug(); + + return await this.driverHelper.waitVisibilityBoolean(OcpLoginPage.LOGIN_PROVIDER_BUTTON, 3, 5000); + } + + async isAuthorizeOpenShiftIdentityProviderPageVisible(): Promise { + Logger.debug(); + + return await this.driverHelper.isVisible(OcpLoginPage.AUTHORIZE_OPENSHIFT_ACCESS_HEADER); + } + + async clickOnApproveAuthorizeAccessButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OcpLoginPage.APPROVE_ACCESS_BUTTON); + } + + async enterUserNameOpenShift(userName: string): Promise { + Logger.debug(`"${userName}"`); + + await this.driverHelper.enterValue(OcpLoginPage.USERNAME_INPUT, userName); + } + + async enterPasswordOpenShift(userPassword: string): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(OcpLoginPage.PASSWORD_INPUT, userPassword); + } + + async clickOnLoginButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OcpLoginPage.LOGIN_BUTTON); + } + + async waitDisappearanceOpenShiftLoginWelcomePage(): Promise { + Logger.debug(); + + await this.driverHelper.waitDisappearance(OcpLoginPage.LOGIN_PAGE_WELCOME_MESSAGE); + } +>>>>>>> main +} diff --git a/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts b/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts index aa2b208dd4f..18b123b429d 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 @@ -8,11 +8,11 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ import 'reflect-metadata'; -import { injectable, inject } from 'inversify'; +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,36 @@ import { Logger } from '../../../utils/Logger'; @injectable() export class OcpRedHatLoginPage implements ICheLoginPage { + private static readonly OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON: By = By.xpath( + '//div[@class="panel-login"]/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('OcpRedHatLoginPage.login'); - - Logger.debug('OcpRedHatLoginPage.login wait for LogInWithOpenShift page and click button'); - await this.driverHelper.waitPresence(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); - - await this.ocpLogin.isIdentityProviderLinkVisible(); - await this.ocpLogin.clickOnLoginProviderTitle(); - - await this.redHatLogin.waitRedHatLoginWelcomePage(); - await this.redHatLogin.enterUserNameRedHat(); - await this.redHatLogin.clickNextButton(); - await this.redHatLogin.enterPasswordRedHat(); - await this.redHatLogin.clickOnLoginButton(); - await this.redHatLogin.waitDisappearanceRedHatLoginWelcomePage(); - } + async login(): Promise { + Logger.debug(); + await this.driverHelper.waitAndClick( + OcpRedHatLoginPage.OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON, + TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT + ); + await this.ocpLogin.waitAndClickOnLoginProviderTitle(); + await this.redHatLogin.waitRedHatLoginWelcomePage(); + try { + await this.redHatLogin.waitAndConfirmCookiePolicy(); + } catch (err) { + Logger.warn('Cookie confirmation dialog not present, continuing...'); + Logger.warn(`${err}`); + } + 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/OcpRedHatLoginPage.ts.orig b/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts.orig new file mode 100644 index 00000000000..b652549514a --- /dev/null +++ b/tests/e2e/pageobjects/login/openshift/OcpRedHatLoginPage.ts.orig @@ -0,0 +1,97 @@ +<<<<<<< HEAD +/********************************************************************* + * Copyright (c) 2019 Red Hat, Inc. +======= +/** ******************************************************************* + * copyright (c) 2019 Red Hat, Inc. +>>>>>>> main + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +<<<<<<< HEAD +import { injectable, inject } from 'inversify'; +import { RedHatLoginPage } from './RedHatLoginPage'; +import { CLASSES } from '../../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { TimeoutConstants } from '../../../constants/TimeoutConstants'; +======= +import { inject, injectable } from 'inversify'; +import { RedHatLoginPage } from './RedHatLoginPage'; +import { CLASSES } from '../../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; +>>>>>>> main +import { ICheLoginPage } from '../interfaces/ICheLoginPage'; +import { OcpLoginPage } from './OcpLoginPage'; +import { DriverHelper } from '../../../utils/DriverHelper'; +import { Logger } from '../../../utils/Logger'; + +@injectable() +export class OcpRedHatLoginPage implements ICheLoginPage { +<<<<<<< HEAD + + private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR: string = `//div[@class='panel-login']`; + private readonly OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR: string = `${this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR}/div[contains(@class, 'panel-content')]/form/button`; + + constructor( + @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage, + @inject(CLASSES.RedHatLoginPage) private readonly redHatLogin: RedHatLoginPage, + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + + async login(): Promise { + Logger.debug('OcpRedHatLoginPage.login'); + + Logger.debug('OcpRedHatLoginPage.login wait for LogInWithOpenShift page and click button'); + await this.driverHelper.waitPresence(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); + + await this.ocpLogin.isIdentityProviderLinkVisible(); + await this.ocpLogin.clickOnLoginProviderTitle(); + + await this.redHatLogin.waitRedHatLoginWelcomePage(); + await this.redHatLogin.enterUserNameRedHat(); + await this.redHatLogin.clickNextButton(); + await this.redHatLogin.enterPasswordRedHat(); + await this.redHatLogin.clickOnLoginButton(); + await this.redHatLogin.waitDisappearanceRedHatLoginWelcomePage(); + } +======= + private static readonly OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON: By = By.xpath( + '//div[@class="panel-login"]/div[contains(@class, "panel-content")]/form/button' + ); + + constructor( + @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage, + @inject(CLASSES.RedHatLoginPage) + private readonly redHatLogin: RedHatLoginPage, + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async login(): Promise { + Logger.debug(); + await this.driverHelper.waitAndClick( + OcpRedHatLoginPage.OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON, + TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT + ); + await this.ocpLogin.waitAndClickOnLoginProviderTitle(); + await this.redHatLogin.waitRedHatLoginWelcomePage(); + try { + await this.redHatLogin.waitAndConfirmCookiePolicy(); + } catch (err) { + Logger.warn('Cookie confirmation dialog not present, continuing...'); + Logger.warn(`${err}`); + } + await this.redHatLogin.enterUserNameRedHat(); + await this.redHatLogin.clickNextButton(); + await this.redHatLogin.enterPasswordRedHat(); + await this.redHatLogin.clickOnLoginButton(); + await this.redHatLogin.waitDisappearanceRedHatLoginWelcomePage(); + } +>>>>>>> main +} diff --git a/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts b/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts index d40ee5fdee5..a242e5f53b2 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 @@ -9,30 +9,27 @@ **********************************************************************/ import 'reflect-metadata'; import { IOcpLoginPage } from '../interfaces/IOcpLoginPage'; -import { injectable, inject } from 'inversify'; +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('OcpUserLoginPage.login'); - - 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 (await this.ocpLogin.isIdentityProviderLinkVisible()) { + await this.ocpLogin.waitAndClickOnLoginProviderTitle(); + } + await this.ocpLogin.waitOpenShiftLoginWelcomePage(); + await this.ocpLogin.enterUserNameOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); + await this.ocpLogin.enterPasswordOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); + await this.ocpLogin.clickOnLoginButton(); + await this.ocpLogin.waitDisappearanceOpenShiftLoginWelcomePage(); + } } diff --git a/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts.orig b/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts.orig new file mode 100644 index 00000000000..716eddc5e97 --- /dev/null +++ b/tests/e2e/pageobjects/login/openshift/OcpUserLoginPage.ts.orig @@ -0,0 +1,69 @@ +<<<<<<< HEAD +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. +======= +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. +>>>>>>> main + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +import { IOcpLoginPage } from '../interfaces/IOcpLoginPage'; +<<<<<<< HEAD +import { injectable, inject } from 'inversify'; +import { OcpLoginPage } from './OcpLoginPage'; +import { CLASSES } from '../../../configs/inversify.types'; +import { Logger } from '../../../utils/Logger'; +import { OAuthConstants } from '../../../constants/OAuthConstants'; + +@injectable() +export class OcpUserLoginPage implements IOcpLoginPage { + + constructor( + @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage) { } + + async login(): Promise { + Logger.debug('OcpUserLoginPage.login'); + + 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(); + } + +======= +import { inject, injectable } from 'inversify'; +import { OcpLoginPage } from './OcpLoginPage'; +import { CLASSES } from '../../../configs/inversify.types'; +import { Logger } from '../../../utils/Logger'; +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; + +@injectable() +export class OcpUserLoginPage implements IOcpLoginPage { + constructor(@inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage) {} + + async login(): Promise { + Logger.debug(); + + if (await this.ocpLogin.isIdentityProviderLinkVisible()) { + await this.ocpLogin.waitAndClickOnLoginProviderTitle(); + } + + await this.ocpLogin.waitOpenShiftLoginWelcomePage(); + await this.ocpLogin.enterUserNameOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); + await this.ocpLogin.enterPasswordOpenShift(OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); + await this.ocpLogin.clickOnLoginButton(); + await this.ocpLogin.waitDisappearanceOpenShiftLoginWelcomePage(); + } +>>>>>>> main +} diff --git a/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts b/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts index ca0d0e1ef80..03666aa108c 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 @@ -8,53 +8,73 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ import 'reflect-metadata'; -import { injectable, inject } from 'inversify'; +import { inject, injectable } from 'inversify'; 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'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; @injectable() export class RedHatLoginPage { - private readonly USERNAME_INPUT_ID: string = 'username-verification'; - private readonly PASSWORD_INPUT_ID: string = 'password'; - private readonly NEXT_BUTTON_ID: string = 'login-show-step2'; - private readonly LOGIN_BUTTON_ID: string = 'rh-password-verification-submit-button'; - - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } - - async waitRedHatLoginWelcomePage(): Promise { - Logger.debug('RedHatLoginPage.waitRedHatLoginWelcomePage'); - await this.driverHelper.waitVisibility(By.id(this.USERNAME_INPUT_ID)); - } - - async enterPasswordRedHat(): Promise { - Logger.debug('RedHatLoginPage.enterPasswordRedHat'); - 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('RedHatLoginPage.clickOnLoginButton'); - const loginButtonLocator: By = By.id(this.LOGIN_BUTTON_ID); - await this.driverHelper.waitAndClick(loginButtonLocator); - } - async waitDisappearanceRedHatLoginWelcomePage(): Promise { - Logger.debug('RedHatLoginPage.waitDisappearanceRedHatLoginWelcomePage'); - await this.driverHelper.waitDisappearance(By.id(this.LOGIN_BUTTON_ID)); - } - async enterUserNameRedHat(): Promise { - Logger.debug('RedHatLoginPage.enterUserNameRedHat'); - 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('RedHatLoginPage.clickNextButton'); - const nextButtonLocator: By = By.id(this.NEXT_BUTTON_ID); - await this.driverHelper.waitAndClick(nextButtonLocator); - } + private static readonly USERNAME_INPUT: By = By.id('username-verification'); + private static readonly PASSWORD_INPUT: By = By.id('password'); + private static readonly NEXT_BUTTON: By = By.id('login-show-step2'); + private static readonly LOGIN_BUTTON: By = By.id('rh-password-verification-submit-button'); + private static readonly COOKIE_DIALOG_IFRAME: By = By.xpath('//div[@class="truste_box_overlay"]//iframe[@class="truste_popframe"]'); + private static readonly COOKIE_DIALOG_BUTTON: By = By.xpath('//div[@class="pdynamicbutton"]//a[@class="call"]'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async waitRedHatLoginWelcomePage(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(RedHatLoginPage.USERNAME_INPUT, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + async waitAndConfirmCookiePolicy(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(RedHatLoginPage.COOKIE_DIALOG_IFRAME, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper + .getDriver() + .switchTo() + .frame(await this.driverHelper.getDriver().findElement(RedHatLoginPage.COOKIE_DIALOG_IFRAME)); + await this.driverHelper.waitAndClick(RedHatLoginPage.COOKIE_DIALOG_BUTTON, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper.refreshPage(); + } + + async enterPasswordRedHat(): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(RedHatLoginPage.PASSWORD_INPUT, OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); + } + + async clickOnLoginButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(RedHatLoginPage.LOGIN_BUTTON); + } + + async waitDisappearanceRedHatLoginWelcomePage(): Promise { + Logger.debug(); + + await this.driverHelper.waitDisappearance(RedHatLoginPage.LOGIN_BUTTON); + } + + async enterUserNameRedHat(): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(RedHatLoginPage.USERNAME_INPUT, OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); + } + + async clickNextButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(RedHatLoginPage.NEXT_BUTTON); + } } diff --git a/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts.orig b/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts.orig new file mode 100644 index 00000000000..0c798d90546 --- /dev/null +++ b/tests/e2e/pageobjects/login/openshift/RedHatLoginPage.ts.orig @@ -0,0 +1,136 @@ +<<<<<<< HEAD +/********************************************************************* + * Copyright (c) 2019 Red Hat, Inc. +======= +/** ******************************************************************* + * copyright (c) 2019 Red Hat, Inc. +>>>>>>> main + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +<<<<<<< HEAD +import { injectable, inject } from 'inversify'; +======= +import { inject, injectable } from 'inversify'; +>>>>>>> main +import { By } from 'selenium-webdriver'; +import { CLASSES } from '../../../configs/inversify.types'; +import { DriverHelper } from '../../../utils/DriverHelper'; +import { Logger } from '../../../utils/Logger'; +<<<<<<< HEAD +import { OAuthConstants } from '../../../constants/OAuthConstants'; + +@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('RedHatLoginPage.waitRedHatLoginWelcomePage'); + await this.driverHelper.waitVisibility(By.id(this.USERNAME_INPUT_ID)); + } + + async enterPasswordRedHat(): Promise { + Logger.debug('RedHatLoginPage.enterPasswordRedHat'); + 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('RedHatLoginPage.clickOnLoginButton'); + const loginButtonLocator: By = By.id(this.LOGIN_BUTTON_ID); + await this.driverHelper.waitAndClick(loginButtonLocator); + } + async waitDisappearanceRedHatLoginWelcomePage(): Promise { + Logger.debug('RedHatLoginPage.waitDisappearanceRedHatLoginWelcomePage'); + await this.driverHelper.waitDisappearance(By.id(this.LOGIN_BUTTON_ID)); + } + async enterUserNameRedHat(): Promise { + Logger.debug('RedHatLoginPage.enterUserNameRedHat'); + 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('RedHatLoginPage.clickNextButton'); + const nextButtonLocator: By = By.id(this.NEXT_BUTTON_ID); + await this.driverHelper.waitAndClick(nextButtonLocator); + } +======= +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; + +@injectable() +export class RedHatLoginPage { + private static readonly USERNAME_INPUT: By = By.id('username-verification'); + private static readonly PASSWORD_INPUT: By = By.id('password'); + private static readonly NEXT_BUTTON: By = By.id('login-show-step2'); + private static readonly LOGIN_BUTTON: By = By.id('rh-password-verification-submit-button'); + private static readonly COOKIE_DIALOG_IFRAME: By = By.xpath('//div[@class="truste_box_overlay"]//iframe[@class="truste_popframe"]'); + private static readonly COOKIE_DIALOG_BUTTON: By = By.xpath('//div[@class="pdynamicbutton"]//a[@class="call"]'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async waitRedHatLoginWelcomePage(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(RedHatLoginPage.USERNAME_INPUT, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + async waitAndConfirmCookiePolicy(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(RedHatLoginPage.COOKIE_DIALOG_IFRAME, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper + .getDriver() + .switchTo() + .frame(await this.driverHelper.getDriver().findElement(RedHatLoginPage.COOKIE_DIALOG_IFRAME)); + await this.driverHelper.waitAndClick(RedHatLoginPage.COOKIE_DIALOG_BUTTON, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper.refreshPage(); + } + + async enterPasswordRedHat(): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(RedHatLoginPage.PASSWORD_INPUT, OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD); + } + + async clickOnLoginButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(RedHatLoginPage.LOGIN_BUTTON); + } + + async waitDisappearanceRedHatLoginWelcomePage(): Promise { + Logger.debug(); + + await this.driverHelper.waitDisappearance(RedHatLoginPage.LOGIN_BUTTON); + } + + async enterUserNameRedHat(): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(RedHatLoginPage.USERNAME_INPUT, OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); + } + + async clickNextButton(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(RedHatLoginPage.NEXT_BUTTON); + } +>>>>>>> main +} diff --git a/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts b/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts index 12449ca11b1..073a3bba357 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 @@ -10,44 +10,49 @@ import 'reflect-metadata'; import { ICheLoginPage } from '../interfaces/ICheLoginPage'; import { OcpLoginPage } from './OcpLoginPage'; -import { injectable, inject } from 'inversify'; +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('RegularUserOcpCheLoginPage.login'); - - Logger.debug('RegularUserOcpCheLoginPage.login wait for LogInWithOpenShift page and click button'); - await this.driverHelper.waitPresence(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); - - 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 static readonly OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON: By = By.xpath( + '//div[@class="panel-login"]/div[contains(@class, "panel-content")]/form/button' + ); + + constructor( + @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage, + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async login( + userName: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME, + password: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD + ): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick( + RegularUserOcpCheLoginPage.OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON, + TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT + ); + + if (await this.ocpLogin.isIdentityProviderLinkVisible()) { + await this.ocpLogin.waitAndClickOnLoginProviderTitle(); + } + + await this.ocpLogin.waitOpenShiftLoginWelcomePage(); + await this.ocpLogin.enterUserNameOpenShift(userName); + await this.ocpLogin.enterPasswordOpenShift(password); + await this.ocpLogin.clickOnLoginButton(); + await this.ocpLogin.waitDisappearanceOpenShiftLoginWelcomePage(); + + if (await this.ocpLogin.isAuthorizeOpenShiftIdentityProviderPageVisible()) { + await this.ocpLogin.clickOnApproveAuthorizeAccessButton(); + } + } } diff --git a/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts.orig b/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts.orig new file mode 100644 index 00000000000..85ecd31a902 --- /dev/null +++ b/tests/e2e/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts.orig @@ -0,0 +1,106 @@ +<<<<<<< HEAD +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. +======= +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. +>>>>>>> main + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +import { ICheLoginPage } from '../interfaces/ICheLoginPage'; +import { OcpLoginPage } from './OcpLoginPage'; +<<<<<<< HEAD +import { injectable, inject } from 'inversify'; +import { CLASSES } from '../../../configs/inversify.types'; +import { Logger } from '../../../utils/Logger'; +import { TimeoutConstants } from '../../../constants/TimeoutConstants'; +import { By } from 'selenium-webdriver'; +import { DriverHelper } from '../../../utils/DriverHelper'; +import { OAuthConstants } from '../../../constants/OAuthConstants'; + +@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('RegularUserOcpCheLoginPage.login'); + + Logger.debug('RegularUserOcpCheLoginPage.login wait for LogInWithOpenShift page and click button'); + await this.driverHelper.waitPresence(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_LOCATOR), TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + await this.driverHelper.waitAndClick(By.xpath(this.OPEN_SHIFT_LOGIN_LANDING_PAGE_BUTTON_LOCATOR)); + + 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(); + } + } +======= +import { inject, injectable } from 'inversify'; +import { CLASSES } from '../../../configs/inversify.types'; +import { Logger } from '../../../utils/Logger'; +import { TIMEOUT_CONSTANTS } from '../../../constants/TIMEOUT_CONSTANTS'; +import { By } from 'selenium-webdriver'; +import { DriverHelper } from '../../../utils/DriverHelper'; +import { OAUTH_CONSTANTS } from '../../../constants/OAUTH_CONSTANTS'; + +@injectable() +export class RegularUserOcpCheLoginPage implements ICheLoginPage { + private static readonly OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON: By = By.xpath( + '//div[@class="panel-login"]/div[contains(@class, "panel-content")]/form/button' + ); + + constructor( + @inject(CLASSES.OcpLoginPage) private readonly ocpLogin: OcpLoginPage, + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async login( + userName: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME, + password: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD + ): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick( + RegularUserOcpCheLoginPage.OPENSHIFT_LOGIN_LANDING_PAGE_BUTTON, + TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT + ); + + if (await this.ocpLogin.isIdentityProviderLinkVisible()) { + await this.ocpLogin.waitAndClickOnLoginProviderTitle(); + } + + await this.ocpLogin.waitOpenShiftLoginWelcomePage(); + await this.ocpLogin.enterUserNameOpenShift(userName); + await this.ocpLogin.enterPasswordOpenShift(password); + await this.ocpLogin.clickOnLoginButton(); + await this.ocpLogin.waitDisappearanceOpenShiftLoginWelcomePage(); + + if (await this.ocpLogin.isAuthorizeOpenShiftIdentityProviderPageVisible()) { + await this.ocpLogin.clickOnApproveAuthorizeAccessButton(); + } + } +>>>>>>> main +} diff --git a/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts b/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts index e4aeec1fb25..018c95bf240 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,32 @@ 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: By = By.xpath('//*[@data-test-id="base-node-handler"]'); + private static readonly EDIT_SOURCE_CODE_ICON: 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(`${this.constructor.name}.${this.waitApplicationIcon.name}`); + await this.driverHelper.waitPresence(OcpApplicationPage.APPLICATION_ICON, 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(); - async waitAndOpenEditSourceCodeIcon(): Promise { - Logger.debug(`${this.constructor.name}.${this.waitAndOpenEditSourceCodeIcon.name}`); - const parentGUID: string = await this.browserTabsUtil.getCurrentWindowHandle(); - await this.driverHelper.waitAndClick(OcpApplicationPage.EDIT_SOURCE_CODE_ICON_LOCATOR); - await this.browserTabsUtil.waitAndSwitchToAnotherWindow(parentGUID, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + const parentGUID: string = await this.browserTabsUtil.getCurrentWindowHandle(); + await this.driverHelper.waitAndClick(OcpApplicationPage.EDIT_SOURCE_CODE_ICON); + await this.browserTabsUtil.waitAndSwitchToAnotherWindow(parentGUID, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } } diff --git a/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts b/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts index 4e9ea3abb38..f658bba984b 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,70 @@ import { e2eContainer } from '../../configs/inversify.config'; @injectable() export class OcpImportFromGitPage { - - private static readonly GIT_URL_INPUT_LOCATOR: By = By.id('form-input-git-url-field'); - private static readonly SHOW_ADVANCED_GIT_OPTIONS_LINK_LOCATOR: By = By.xpath('//*[text()="Show advanced Git options"]//ancestor::button'); - private static readonly HIDE_ADVANCED_GIT_OPTIONS_LOCATOR: By = By.xpath('//*[text()="Hide advanced Git options"]'); - private static readonly GIT_REFERENCE_INPUT_LOCATOR: By = By.id('form-input-git-ref-field'); - private static readonly EDIT_IMPORT_STRATEGY_LINK_LOCATOR: By = By.xpath('//*[text()="Edit Import Strategy"]//ancestor::button'); - private static readonly BUILDER_IMAGE_STRATEGY_ITEM_LOCATOR: By = By.xpath('//*[text()="Builder Image"]//parent::div//parent::div'); - private static readonly ADD_LABEL_LINK_LOCATOR: By = By.xpath('//button[text()="Labels"]'); - private static readonly ADD_LABEL_INPUT_LOCATOR: By = By.id('form-selector-labels-field'); - private static readonly SUBMIT_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="submit-button"]'); - - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { - } - - async enterGitRepoUrl(gitRepoUrl: string): Promise { - Logger.debug(`${this.constructor.name}.${this.enterGitRepoUrl.name} "${gitRepoUrl}"`); - - await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_URL_INPUT_LOCATOR, gitRepoUrl); - } - - async clickOnAdvancedOptionsButton(): Promise { - Logger.debug(`${this.constructor.name}.${this.clickOnAdvancedOptionsButton.name}`); - - if (!(await this.driverHelper.isVisible(OcpImportFromGitPage.HIDE_ADVANCED_GIT_OPTIONS_LOCATOR))) { - await this.driverHelper.waitAndClick(OcpImportFromGitPage.SHOW_ADVANCED_GIT_OPTIONS_LINK_LOCATOR); - } - } - - async enterGitReference(gitReference: string): Promise { - Logger.debug(`${this.constructor.name}.${this.enterGitReference.name} "${gitReference}"`); - - await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_REFERENCE_INPUT_LOCATOR, gitReference); - } - - async selectBuilderImageImportStrategy(): Promise { - Logger.debug(`${this.constructor.name}.${this.selectBuilderImageImportStrategy.name}`); - - await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.EDIT_IMPORT_STRATEGY_LINK_LOCATOR); - await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.BUILDER_IMAGE_STRATEGY_ITEM_LOCATOR); - } - - async addLabel(label: string): Promise { - Logger.debug(`${this.constructor.name}.${this.addLabel.name} "${label}"`); - - await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.ADD_LABEL_LINK_LOCATOR); - await this.driverHelper.scrollToAndEnterValue(OcpImportFromGitPage.ADD_LABEL_INPUT_LOCATOR, label); - } - - async submitConfiguration(): Promise { - Logger.debug(`${this.constructor.name}.${this.submitConfiguration.name}`); - - await this.driverHelper.waitAndClick(OcpImportFromGitPage.SUBMIT_BUTTON_LOCATOR); - return e2eContainer.get(CLASSES.OcpApplicationPage); - } - - async fitAndSubmitConfiguration(gitRepoUrl: string, gitReference: string, label: string): Promise { - Logger.debug(`${this.constructor.name}.${this.fitAndSubmitConfiguration.name}`); - - await this.enterGitRepoUrl(gitRepoUrl); - await this.clickOnAdvancedOptionsButton(); - await this.enterGitReference(gitReference); - await this.selectBuilderImageImportStrategy(); - await this.addLabel(label); - return await this.submitConfiguration(); - } + private static readonly GIT_URL_INPUT: By = By.id('form-input-git-url-field'); + private static readonly SHOW_ADVANCED_GIT_OPTIONS_LINK: By = By.xpath('//*[text()="Show advanced Git options"]//ancestor::button'); + private static readonly HIDE_ADVANCED_GIT_OPTIONS: By = By.xpath('//*[text()="Hide advanced Git options"]'); + private static readonly GIT_REFERENCE_INPUT: By = By.id('form-input-git-ref-field'); + private static readonly EDIT_IMPORT_STRATEGY_LINK: By = By.xpath('//*[text()="Edit Import Strategy"]//ancestor::button'); + private static readonly BUILDER_IMAGE_STRATEGY_ITEM: By = By.xpath('//*[text()="Builder Image"]//parent::div//parent::div'); + private static readonly ADD_LABEL_LINK: By = By.xpath('//button[text()="Labels"]'); + private static readonly ADD_LABEL_INPUT: By = By.id('form-selector-labels-field'); + private static readonly SUBMIT_BUTTON: By = By.xpath('//*[@data-test-id="submit-button"]'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async enterGitRepoUrl(gitRepoUrl: string): Promise { + Logger.debug(); + + await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_URL_INPUT, gitRepoUrl); + } + + async clickOnAdvancedOptionsButton(): Promise { + Logger.debug(); + + if (!(await this.driverHelper.isVisible(OcpImportFromGitPage.HIDE_ADVANCED_GIT_OPTIONS))) { + await this.driverHelper.waitAndClick(OcpImportFromGitPage.SHOW_ADVANCED_GIT_OPTIONS_LINK); + } + } + + async enterGitReference(gitReference: string): Promise { + Logger.debug(`"${gitReference}"`); + + await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_REFERENCE_INPUT, gitReference); + } + + async selectBuilderImageImportStrategy(): Promise { + Logger.debug(); + + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.EDIT_IMPORT_STRATEGY_LINK); + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.BUILDER_IMAGE_STRATEGY_ITEM); + } + + async addLabel(label: string): Promise { + Logger.debug(`"${label}"`); + + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.ADD_LABEL_LINK); + await this.driverHelper.scrollToAndEnterValue(OcpImportFromGitPage.ADD_LABEL_INPUT, label); + } + + async submitConfiguration(): Promise { + Logger.debug(); + + await this.driverHelper.waitAndClick(OcpImportFromGitPage.SUBMIT_BUTTON); + 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 8f8cd174c2b..41dcd8f4ac2 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: By = By.id('page-main-header'); + private static readonly SELECT_ROLE_BUTTON: By = By.xpath('//*[@data-test-id="perspective-switcher-toggle"]'); + private static readonly ADD_BUTTON: By = By.xpath('//*[@data-test-id="+Add-header"]'); + private static readonly IMPORT_FROM_GIT_ITEM: By = By.xpath('//*[@data-test="item import-from-git"]'); + private static readonly SELECT_PROJECT_DROPDOWN: By = By.xpath('//div[@class="co-namespace-dropdown"]//button'); + private static readonly PROJECT_FILTER_INPUT: By = By.xpath('//*[@data-test="dropdown-text-filter"]'); + private static readonly SKIP_TOUR_BUTTON: By = By.xpath('//*[text()="Skip tour"]'); - 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}"]`); - } + async waitOpenMainPage(): Promise { + Logger.debug(); - private static getProjectDropdownItemLocator(projectName: string): By { - return By.xpath(`//button//*[text()="${projectName}"]`); - } + await this.driverHelper.waitVisibility(OcpMainPage.MAIN_PAGE_HEADER, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + async clickOnSelectRoleButton(): Promise { + Logger.debug(); - async waitOpenMainPage(): Promise { - Logger.debug(`${this.constructor.name}.${this.waitOpenMainPage.name}`); + await this.driverHelper.waitAndClick(OcpMainPage.SELECT_ROLE_BUTTON); + } - await this.driverHelper.waitVisibility(OcpMainPage.MAIN_PAGE_HEADER_LOCATOR, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); - } + async clickAddToProjectButton(): Promise { + Logger.debug(); - async clickOnSelectRoleButton(): Promise { - Logger.debug(`${this.constructor.name}.${this.clickOnSelectRoleButton.name}`); + await this.driverHelper.waitAndClick(OcpMainPage.ADD_BUTTON); + } - await this.driverHelper.waitAndClick(OcpMainPage.SELECT_ROLE_BUTTON_LOCATOR); - } + async selectDeveloperRole(): Promise { + Logger.debug(); - async clickAddToProjectButton(): Promise { - Logger.debug(`${this.constructor.name}.${this.clickAddToProjectButton.name}`); + await this.waitOpenMainPage(); + await this.tryToSkipWebTour(); + await this.clickOnSelectRoleButton(); + await this.selectRole('Developer'); + await this.tryToSkipWebTour(); + } - await this.driverHelper.waitAndClick(OcpMainPage.ADD_BUTTON_LOCATOR); - } + async selectImportFromGitMethod(): Promise { + Logger.debug(); - async selectDeveloperRole(): Promise { - Logger.debug(`${this.constructor.name}.${this.selectDeveloperRole.name}`); + await this.driverHelper.waitAndClick(OcpMainPage.IMPORT_FROM_GIT_ITEM); + return e2eContainer.get(CLASSES.OcpImportFromGitPage); + } - await this.waitOpenMainPage(); - await this.tryToSkipWebTour(); - await this.clickOnSelectRoleButton(); - await this.selectRole('Developer'); - await this.tryToSkipWebTour(); - } + async openImportFromGitPage(): Promise { + Logger.debug(); - async selectImportFromGitMethod(): Promise { - Logger.debug(`${this.constructor.name}.${this.selectImportFromGitMethod.name}`); + await this.clickAddToProjectButton(); + return await this.selectImportFromGitMethod(); + } - await this.driverHelper.waitAndClick(OcpMainPage.IMPORT_FROM_GIT_ITEM_LOCATOR); - return e2eContainer.get(CLASSES.OcpImportFromGitPage); - } + async selectProject(projectName: string): Promise { + Logger.debug(); - async openImportFromGitPage(): Promise { - Logger.debug(`${this.constructor.name}.${this.openImportFromGitPage.name}`); + await this.driverHelper.waitAndClick(OcpMainPage.SELECT_PROJECT_DROPDOWN); + await this.driverHelper.enterValue(OcpMainPage.PROJECT_FILTER_INPUT, projectName); + await this.driverHelper.waitAndClick(this.getProjectDropdownItemLocator(projectName)); + } - await this.clickAddToProjectButton(); - return await this.selectImportFromGitMethod(); - } + private getRoleLocator(role: string): By { + return By.xpath(`//a//*[text()="${role}"]`); + } - async selectProject(projectName: string): Promise { - Logger.debug(`${this.constructor.name}.${this.selectProject.name}`); + private getProjectDropdownItemLocator(projectName: string): By { + return By.xpath(`//button//*[text()="${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(`${this.constructor.name}.${this.selectRole.name} - selecting role ${role}`); + await this.driverHelper.waitAndClick(this.getRoleLocator(role)); + } - await this.driverHelper.waitAndClick(OcpMainPage.getRoleLocator(role)); - } + private async tryToSkipWebTour(): Promise { + Logger.debug(); - private async tryToSkipWebTour(): Promise { - Logger.debug(`${this.constructor.name}.${this.tryToSkipWebTour.name}`); + if (await this.driverHelper.isVisible(OcpMainPage.SKIP_TOUR_BUTTON)) { + await this.driverHelper.waitAndClick(OcpMainPage.SKIP_TOUR_BUTTON); - if (await this.driverHelper.isVisible(OcpMainPage.SKIP_TOUR_BUTTON_LOCATOR)) { - await this.driverHelper.waitAndClick(OcpMainPage.SKIP_TOUR_BUTTON_LOCATOR); - - Logger.debug(`${this.constructor.name}.${this.tryToSkipWebTour.name} - Welcome tour modal dialog was located and skipped`); - } else { - Logger.debug(`${this.constructor.name}.${this.tryToSkipWebTour.name} - 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/pageobjects/webterminal/WebTerminalPage.ts b/tests/e2e/pageobjects/webterminal/WebTerminalPage.ts new file mode 100644 index 00000000000..54d4ccf9c16 --- /dev/null +++ b/tests/e2e/pageobjects/webterminal/WebTerminalPage.ts @@ -0,0 +1,181 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +import { inject, injectable } from 'inversify'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { CLASSES } from '../../configs/inversify.types'; +import { By, Key } from 'selenium-webdriver'; +import { Logger } from '../../utils/Logger'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; + +export enum TimeUnits { + Seconds = 'Seconds', + Minutes = 'Minutes', + Hours = 'Hours' +} +@injectable() +export class WebTerminalPage { + private static readonly TIMEOUT_BUTTON: By = By.xpath('//button[(text()="Timeout")]'); + private static readonly IMAGE_BUTTON: By = By.xpath('//button[(text()="Image")]'); + private static readonly WEB_TERMINAL_BUTTON: By = By.xpath('//button[@data-quickstart-id="qs-masthead-cloudshell"]'); + private static readonly WEB_TERMINAL_PAGE: By = By.xpath('//*[@class="xterm-helper-textarea"]'); + private static readonly START_WT_COMMAND_LINE_TERMINAL_BUTTON: By = By.css('button[data-test-id="submit-button"]'); + private static readonly WEB_TERMINAL_PROJECT_SELECTION_DROPDOWN: By = By.css('input#form-input-namespace-field'); + private static readonly WEB_TERMINAL_PROJECT_CANCEL_BUTTON: By = By.css('button[data-test-id="reset-button"]'); + private static readonly TERMINAL_INACTIVITY_MESS: By = By.xpath('//div[contains(text(),"The terminal connection has closed")]'); + private static readonly RESTART_BUTTON: By = By.xpath('//button[text()="Restart terminal"]'); + private static readonly PROJECT_NAMESPACE_DROP_DAWN: By = By.css('button#form-ns-dropdown-namespace-field'); + private static readonly PROJECT_SELECTION_FIELD: By = By.css('input[data-test-id="dropdown-text-filter"]'); + private static readonly PROJECT_NAME_FIELD: By = By.css('input#form-input-newNamespace-field'); + private static readonly TIMEOUT_INPUT: By = By.css( + 'input[aria-describedby="form-resource-limit-advancedOptions-timeout-limit-field-helper"]' + ); + private static readonly INCREMENT_TIMEOUT_BTN: By = By.css('button[data-test-id="Decrement"]'); + private static readonly DECREMENT_TIMEOUT_BTN: By = By.css('button[data-test-id="Increment'); + private static readonly TIME_UNIT_DROP_DAWN: By = By.css('div.request-size-input__unit button'); + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + + async clickOnWebTerminalIcon(): Promise { + Logger.debug(); + await this.driverHelper.waitAndClick(WebTerminalPage.WEB_TERMINAL_BUTTON, TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL); + } + async waitTerminalIsStarted(): Promise { + Logger.debug(); + await this.driverHelper.waitPresence(WebTerminalPage.WEB_TERMINAL_PAGE, TIMEOUT_CONSTANTS.TS_WAIT_LOADER_ABSENCE_TIMEOUT); + } + async clickOnStartWebTerminalButton(): Promise { + Logger.debug(); + await this.driverHelper.waitAndClick(WebTerminalPage.START_WT_COMMAND_LINE_TERMINAL_BUTTON); + } + async getAdminProjectName(): Promise { + Logger.debug(); + return await this.driverHelper.waitAndGetValue( + By.css('input#form-input-namespace-field'), + TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL + ); + } + async openWebTerminal(): Promise { + Logger.debug(); + await this.clickOnWebTerminalIcon(); + await this.clickOnStartWebTerminalButton(); + await this.waitTerminalIsStarted(); + } + async waitDisabledProjectFieldAndGetProjectName(): Promise { + Logger.debug(); + return await this.driverHelper.waitAndGetElementAttribute(WebTerminalPage.WEB_TERMINAL_PROJECT_SELECTION_DROPDOWN, 'value'); + } + async typeIntoWebTerminal(text: string): Promise { + Logger.debug(); + await this.driverHelper.waitPresence(WebTerminalPage.WEB_TERMINAL_PAGE, TIMEOUT_CONSTANTS.TS_IDE_LOAD_TIMEOUT); + await this.driverHelper.typeToInvisible(WebTerminalPage.WEB_TERMINAL_PAGE, text); + } + + async typeAndEnterIntoWebTerminal(text: string): Promise { + Logger.debug(); + await this.driverHelper.waitPresence(WebTerminalPage.WEB_TERMINAL_PAGE, TIMEOUT_CONSTANTS.TS_IDE_LOAD_TIMEOUT); + await this.driverHelper.typeToInvisible(WebTerminalPage.WEB_TERMINAL_PAGE, text + Key.ENTER); + } + async clickOnProjectListDropDown(): Promise { + Logger.debug(); + { + await this.driverHelper.waitPresence( + WebTerminalPage.WEB_TERMINAL_PROJECT_SELECTION_DROPDOWN, + TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ); + } + } + async waitTimeoutButton(): Promise { + Logger.debug(); + { + await this.driverHelper.waitPresence(WebTerminalPage.TIMEOUT_BUTTON); + } + } + async waitImageButton(): Promise { + Logger.debug(); + { + await this.driverHelper.waitPresence(WebTerminalPage.IMAGE_BUTTON); + } + } + async waitStartButton(): Promise { + Logger.debug(); + { + await this.driverHelper.waitPresence(WebTerminalPage.START_WT_COMMAND_LINE_TERMINAL_BUTTON); + } + } + + async waitCancelButton(): Promise { + Logger.debug(); + { + await this.driverHelper.waitPresence(WebTerminalPage.WEB_TERMINAL_PROJECT_CANCEL_BUTTON); + } + } + async waitTerminalWidget(): Promise { + Logger.debug(); + await this.waitStartButton(); + await this.waitCancelButton(); + await this.waitTimeoutButton(); + await this.waitImageButton(); + } + async waitTerminalInactivity(customTimeout?: number): Promise { + await this.driverHelper.waitVisibility( + WebTerminalPage.TERMINAL_INACTIVITY_MESS, + TIMEOUT_CONSTANTS.TS_COMMON_PLUGIN_TEST_TIMEOUT || customTimeout + ); + + await this.driverHelper.waitVisibility(WebTerminalPage.RESTART_BUTTON); + } + async waitWebTerminalProjectNameField(): Promise { + await this.driverHelper.waitPresence(WebTerminalPage.PROJECT_NAMESPACE_DROP_DAWN); + } + async typeProjectName(projectName: string): Promise { + await this.waitWebTerminalProjectNameField(); + await this.driverHelper.type(WebTerminalPage.PROJECT_NAME_FIELD, projectName, TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM); + } + async openProjectDropDawn(): Promise { + await this.driverHelper.waitAndClick(WebTerminalPage.PROJECT_NAMESPACE_DROP_DAWN); + } + async typeProjectNameForSelecting(projectName: string): Promise { + await this.driverHelper.type(WebTerminalPage.PROJECT_SELECTION_FIELD, projectName); + } + + async selectProjectFromDropDawnList(projectName: string): Promise { + await this.driverHelper.waitAndClick(By.xpath(`//span[@class="pf-v5-c-menu__item-text" and text()="${projectName}"]`)); + } + + async findAndSelectProject(projectName: string): Promise { + await this.openProjectDropDawn(); + await this.typeProjectNameForSelecting(projectName); + await this.selectProjectFromDropDawnList(projectName); + } + async clickOnTimeoutButton(): Promise { + await this.driverHelper.waitAndClick(WebTerminalPage.TIMEOUT_BUTTON); + } + async setTimeoutByEntering(timeValue: number): Promise { + await this.driverHelper.type(WebTerminalPage.TIMEOUT_INPUT, timeValue.toString()); + } + async clickOnPlusBtn(): Promise { + await this.driverHelper.waitAndClick(WebTerminalPage.INCREMENT_TIMEOUT_BTN); + } + + async clickOnMinutesBtn(): Promise { + await this.driverHelper.waitAndClick(WebTerminalPage.DECREMENT_TIMEOUT_BTN); + } + + async clickOnTimeUnitDropDown(): Promise { + await this.driverHelper.waitAndClick(WebTerminalPage.TIME_UNIT_DROP_DAWN); + } + async selectTimeUnit(timeUnits: TimeUnits): Promise { + await this.driverHelper.waitAndClick(By.xpath(`//button[@data-test-id='dropdown-menu' and text()='${timeUnits}']`)); + } +} diff --git a/tests/e2e/resources/default-devfile.yaml b/tests/e2e/resources/default-devfile.yaml new file mode 100644 index 00000000000..727720d64df --- /dev/null +++ b/tests/e2e/resources/default-devfile.yaml @@ -0,0 +1,27 @@ +kind: DevWorkspace +apiVersion: workspace.devfile.io/v1alpha2 +metadata: + name: default +spec: + started: true + template: + projects: + - name: web-nodejs-sample + git: + remotes: + origin: "https://github.com/che-samples/web-nodejs-sample.git" + commands: + - id: say-hello + exec: + component: che-code-runtime-description + commandLine: echo "Hello from $(pwd)" + workingDir: ${PROJECT_SOURCE}/app + contributions: + - name: che-code + uri: https://eclipse-che.github.io/che-plugin-registry/main/v3/plugins/che-incubator/che-code/latest/devfile.yaml + components: + - name: che-code-runtime-description + container: + env: + - name: CODE_HOST + value: 0.0.0.0 diff --git a/tests/e2e/resources/pod-overrides-airgap.yaml b/tests/e2e/resources/pod-overrides-airgap.yaml new file mode 100644 index 00000000000..32a70ffc715 --- /dev/null +++ b/tests/e2e/resources/pod-overrides-airgap.yaml @@ -0,0 +1,37 @@ +kind: DevWorkspace +apiVersion: workspace.devfile.io/v1alpha2 +metadata: + name: code-latest-pod-overrides +spec: + started: true + template: + attributes: + pod-overrides: + metadata: + annotations: + io.openshift.userns: "true" + io.kubernetes.cri-o.userns-mode: "auto:size=65536;map-to-root=true" # <-- user namespace + openshift.io/scc: container-build + spec: + runtimeClassName: kata + schedulerName: stork + projects: + - name: web-nodejs-sample + git: + remotes: + origin: "https://github.com/che-samples/web-nodejs-sample.git" + commands: + - id: say-hello + exec: + component: che-code-runtime-description + commandLine: echo "Hello from $(pwd)" + workingDir: ${PROJECT_SOURCE}/app + contributions: + - name: che-code + uri: http://plugin-registry.openshift-devspaces.svc.cluster.local:8080/v3/plugins/che-incubator/che-code/latest/devfile.yaml + components: + - name: che-code-runtime-description + container: + env: + - name: CODE_HOST + value: 0.0.0.0 diff --git a/tests/e2e/specs/MochaHooks.ts b/tests/e2e/specs/MochaHooks.ts index e074a6096ad..a005fd5cefc 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,68 +11,119 @@ 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 { allure } from 'allure-mocha/runtime'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; +import { MONACO_CONSTANTS } from '../constants/MONACO_CONSTANTS'; +import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; +import { decorate, injectable, unmanaged } from 'inversify'; +import { Main } from '@eclipse-che/che-devworkspace-generator/lib/main'; +import { LocatorLoader } from 'monaco-page-objects/out/locators/loader'; +import { REPORTER_CONSTANTS } from '../constants/REPORTER_CONSTANTS'; +import { WorkspaceHandlingTests } from '../tests-library/WorkspaceHandlingTests'; const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); - let latestWorkspace: string = ''; +export let rpApi: any = undefined; export function registerRunningWorkspace(workspaceName: string): void { - Logger.debug(`MochaHooks.registerRunningWorkspace with workspaceName:${workspaceName}`); - latestWorkspace = workspaceName; + workspaceName !== '' + ? Logger.debug(`with workspaceName:${workspaceName}`) + : ((): void => { + Logger.debug('delete workspace name'); + WorkspaceHandlingTests.clearWorkspaceName(); + })(); + + 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 initRPApi(): any { + rpApi = require('@reportportal/agent-js-mocha/lib/publicReportingAPI.js'); + }, + + function decorateExternalClasses(): void { + decorate(injectable(), Main); + decorate(injectable(), LocatorLoader); + decorate(unmanaged(), LocatorLoader, 0); + decorate(unmanaged(), LocatorLoader, 1); + decorate(unmanaged(), LocatorLoader, 2); + }, + + 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(); + } + }, + // init vscode-extension-tester monaco-page-objects + function initMonacoPageObjects(): void { + 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 * 2 + }); + } + } + } + ], + afterEach: [ + async function saveAllureAttachments(this: Mocha.Context): Promise { + if (REPORTER_CONSTANTS.SAVE_ALLURE_REPORT_DATA && this.currentTest?.state === 'failed') { + try { + const screenshot: string = await driverHelper.getDriver().takeScreenshot(); + allure.attachment('Screenshot', Buffer.from(screenshot, 'base64'), 'image/png'); + } catch (e) { + allure.attachment('No screenshot', 'Could not take a screenshot', 'text/plain'); + } + } + }, + async function saveReportportalAttachments(this: Mocha.Context): Promise { + if (REPORTER_CONSTANTS.SAVE_RP_REPORT_DATA && this.currentTest?.state === 'failed') { + try { + const screenshot: string = await driverHelper.getDriver().takeScreenshot(); + const attachment: { name: string; type: string; content: string } = { + name: 'screenshot.png', + type: 'image/png', + content: screenshot + }; + rpApi.error('Screenshot on fail: ', attachment); + } catch (e) { + rpApi.error('Could not attach the screenshot'); + } + } + }, + // stop and remove running workspace + async function deleteWorkspaceOnFailedTest(this: Mocha.Context): Promise { + if (this.currentTest?.state === 'failed') { + if (BASE_TEST_CONSTANTS.DELETE_WORKSPACE_ON_FAILED_TEST && CHROME_DRIVER_CONSTANTS.TS_USE_WEB_DRIVER_FOR_TEST) { + Logger.trace( + 'Property DELETE_WORKSPACE_ON_FAILED_TEST is true - trying to stop and delete running workspace with API.' + ); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(latestWorkspace); + } + } + } + ] }; diff --git a/tests/e2e/specs/MochaHooks.ts.orig b/tests/e2e/specs/MochaHooks.ts.orig new file mode 100644 index 00000000000..59a36076509 --- /dev/null +++ b/tests/e2e/specs/MochaHooks.ts.orig @@ -0,0 +1,180 @@ +/** ******************************************************************* + * 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 'reflect-metadata'; +import { CLASSES, TYPES } from '../configs/inversify.types'; +import { CheApiRequestHandler } from '../utils/request-handlers/CheApiRequestHandler'; +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'; +<<<<<<< HEAD +import { BaseTestConstants } from '../constants/BaseTestConstants'; +import { ChromeDriverConstants } from '../constants/ChromeDriverConstants'; +import { MonacoConstants } from '../constants/MonacoConstants'; +======= +import { allure } from 'allure-mocha/runtime'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; +import { MONACO_CONSTANTS } from '../constants/MONACO_CONSTANTS'; +import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; +import { decorate, injectable, unmanaged } from 'inversify'; +import { Main } from '@eclipse-che/che-devworkspace-generator/lib/main'; +import { LocatorLoader } from 'monaco-page-objects/out/locators/loader'; +import { REPORTER_CONSTANTS } from '../constants/REPORTER_CONSTANTS'; +import { WorkspaceHandlingTests } from '../tests-library/WorkspaceHandlingTests'; +>>>>>>> main + +const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); +let latestWorkspace: string = ''; +export let rpApi: any = undefined; + +export function registerRunningWorkspace(workspaceName: string): void { + workspaceName !== '' + ? Logger.debug(`with workspaceName:${workspaceName}`) + : ((): void => { + Logger.debug('delete workspace name'); + WorkspaceHandlingTests.clearWorkspaceName(); + })(); + + latestWorkspace = workspaceName; +} + +exports.mochaHooks = { +<<<<<<< HEAD + 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 initRPApi(): any { + rpApi = require('@reportportal/agent-js-mocha/lib/publicReportingAPI.js'); + }, + + function decorateExternalClasses(): void { + decorate(injectable(), Main); + decorate(injectable(), LocatorLoader); + decorate(unmanaged(), LocatorLoader, 0); + decorate(unmanaged(), LocatorLoader, 1); + decorate(unmanaged(), LocatorLoader, 2); + }, + + 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(); + } + }, + // init vscode-extension-tester monaco-page-objects + function initMonacoPageObjects(): void { + 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 * 2 + }); + } + } + } + ], + afterEach: [ + async function saveAllureAttachments(this: Mocha.Context): Promise { + if (REPORTER_CONSTANTS.SAVE_ALLURE_REPORT_DATA && this.currentTest?.state === 'failed') { + try { + const screenshot: string = await driverHelper.getDriver().takeScreenshot(); + allure.attachment('Screenshot', Buffer.from(screenshot, 'base64'), 'image/png'); + } catch (e) { + allure.attachment('No screenshot', 'Could not take a screenshot', 'text/plain'); + } + } + }, + async function saveReportportalAttachments(this: Mocha.Context): Promise { + if (REPORTER_CONSTANTS.SAVE_RP_REPORT_DATA && this.currentTest?.state === 'failed') { + try { + const screenshot: string = await driverHelper.getDriver().takeScreenshot(); + const attachment: { name: string; type: string; content: string } = { + name: 'screenshot.png', + type: 'image/png', + content: screenshot + }; + rpApi.error('Screenshot on fail: ', attachment); + } catch (e) { + rpApi.error('Could not attach the screenshot'); + } + } + }, + // stop and remove running workspace + async function deleteWorkspaceOnFailedTest(this: Mocha.Context): Promise { + if (this.currentTest?.state === 'failed') { + if (BASE_TEST_CONSTANTS.DELETE_WORKSPACE_ON_FAILED_TEST && CHROME_DRIVER_CONSTANTS.TS_USE_WEB_DRIVER_FOR_TEST) { + Logger.trace( + 'Property DELETE_WORKSPACE_ON_FAILED_TEST is true - trying to stop and delete running workspace with API.' + ); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(latestWorkspace); + } + } + } + ] +>>>>>>> main +}; diff --git a/tests/e2e/specs/SmokeTest.spec.ts b/tests/e2e/specs/SmokeTest.spec.ts index 144c2c1c91f..577cb165e6d 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 @@ -7,47 +7,64 @@ * * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { SideBarView, ViewSection } from 'monaco-page-objects'; +import { ViewSection } from 'monaco-page-objects'; import { ProjectAndFileTests } from '../tests-library/ProjectAndFileTests'; import { CLASSES } from '../configs/inversify.types'; import { e2eContainer } from '../configs/inversify.config'; import { WorkspaceHandlingTests } from '../tests-library/WorkspaceHandlingTests'; 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 { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; -const factoryUrl: string = FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git'; -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -let projectName: string; - -suite(`The SmokeTest userstory`, async function (): Promise { - let projectSection: ViewSection; - suite(`Create workspace from factory:${factoryUrl}`, async function (): Promise { - loginTests.loginIntoChe(); - workspaceHandlingTests.createAndOpenWorkspaceFromGitRepository(factoryUrl); - workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - test('Register running workspace', async () => { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - test('Wait workspace readiness', async function (): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); - test('Check a project folder has been created', async function (): Promise { - projectName = 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 { - const label: string = 'devfile.yaml'; - await projectSection.findItem(label); - Logger.debug(`projectSection.findItem: find ${label}`); - }); - test('Stopping and deleting the workspace', async function (): Promise { - await workspaceHandlingTests.stopAndRemoveWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - }); +suite(`The SmokeTest userstory ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const factoryUrl: string = + FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git'; + let projectSection: ViewSection; + suite(`Create workspace from factory:${factoryUrl}`, function (): void { + suiteSetup('Login', async function (): Promise { + await 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 projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, projectName), 'Project folder was not imported').not + .undefined; + }); + test('Check the project files was imported', async function (): Promise { + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME), + 'Project files were not imported' + ).not.undefined; + }); + test('Stop the workspace by UI', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + test('Delete the workspace by UI', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + }); }); diff --git a/tests/e2e/specs/SmokeTest.spec.ts.orig b/tests/e2e/specs/SmokeTest.spec.ts.orig new file mode 100644 index 00000000000..0033850743f --- /dev/null +++ b/tests/e2e/specs/SmokeTest.spec.ts.orig @@ -0,0 +1,107 @@ +/** ******************************************************************* + * 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 { ViewSection } from 'monaco-page-objects'; +import { ProjectAndFileTests } from '../tests-library/ProjectAndFileTests'; +import { CLASSES } from '../configs/inversify.types'; +import { e2eContainer } from '../configs/inversify.config'; +import { WorkspaceHandlingTests } from '../tests-library/WorkspaceHandlingTests'; +import { registerRunningWorkspace } from './MochaHooks'; +import { LoginTests } from '../tests-library/LoginTests'; +import { StringUtil } from '../utils/StringUtil'; +<<<<<<< HEAD +import { FactoryTestConstants } from '../constants/FactoryTestConstants'; + +const factoryUrl: string = FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git'; +const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); +const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); +const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); +let projectName: string; + +suite(`The SmokeTest userstory`, async function (): Promise { + let projectSection: ViewSection; + suite(`Create workspace from factory:${factoryUrl}`, async function (): Promise { + loginTests.loginIntoChe(); + workspaceHandlingTests.createAndOpenWorkspaceFromGitRepository(factoryUrl); + workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + test('Register running workspace', async () => { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + test('Wait workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + test('Check a project folder has been created', async function (): Promise { + projectName = 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 { + const label: string = 'devfile.yaml'; + await projectSection.findItem(label); + Logger.debug(`projectSection.findItem: find ${label}`); + }); + test('Stopping and deleting the workspace', async function (): Promise { + await workspaceHandlingTests.stopAndRemoveWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + }); +======= +import { FACTORY_TEST_CONSTANTS } from '../constants/FACTORY_TEST_CONSTANTS'; +import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; +import { expect } from 'chai'; +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; + +suite(`The SmokeTest userstory ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const factoryUrl: string = + FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git'; + let projectSection: ViewSection; + suite(`Create workspace from factory:${factoryUrl}`, function (): void { + suiteSetup('Login', async function (): Promise { + await 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 projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, projectName), 'Project folder was not imported').not + .undefined; + }); + test('Check the project files was imported', async function (): Promise { + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME), + 'Project files were not imported' + ).not.undefined; + }); + test('Stop the workspace by UI', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + test('Delete the workspace by UI', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + }); +>>>>>>> main +}); diff --git a/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts b/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts index cb420326e62..b243c6e71e9 100644 --- a/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts +++ b/tests/e2e/specs/api/ContainerOverridesAPI.spec.ts @@ -1,38 +1,52 @@ +/** ******************************************************************* + * 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 { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; -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 ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, 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 = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + kubernetesCommandLineToolsExecutor.workspaceName = workspaceName; + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); - 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 f605591f2bd..996d8950757 100644 --- a/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts +++ b/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts @@ -1,106 +1,127 @@ -import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +/** ******************************************************************* + * 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 { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigurationHelper'; import { ShellString } from 'shelljs'; import { expect } from 'chai'; import { DevfileContext } from '@eclipse-che/che-devworkspace-generator/lib/api/devfile-context'; import { StringUtil } from '../../utils/StringUtil'; -import { DevfilesRegistryHelper } from '../../utils/DevfilesRegistryHelper'; import { Logger } from '../../utils/Logger'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { DevfilesRegistryHelper } from '../../utils/DevfilesRegistryHelper'; +import { MOCHA_CONSTANTS } from '../../constants/MOCHA_CONSTANTS'; +import { API_TEST_CONSTANTS } from '../../constants/API_TEST_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; /** - * Dynamically generating tests + * dynamically generating tests * info: https://mochajs.org/#delayed-root-suite */ - -(async function (): Promise { - - const devfilesRegistryHelper: DevfilesRegistryHelper = new DevfilesRegistryHelper(); - const devfileSamples: any = await devfilesRegistryHelper.collectPathsToDevfilesFromRegistry(); - - for (const devfileSample of devfileSamples) { - suite(`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(); +void (async function (): Promise { + const devfilesRegistryHelper: DevfilesRegistryHelper = e2eContainer.get(CLASSES.DevfilesRegistryHelper); + + let devfileSamples: any = []; + if ( + MOCHA_CONSTANTS.MOCHA_DELAYED_SUITE && + !API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL().includes(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL) + ) { + devfileSamples = await devfilesRegistryHelper.collectPathsToDevfilesFromRegistry(false); + } + for (const devfileSample of devfileSamples) { + suite(`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: 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 = e2eContainer.get(CLASSES.KubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor.workspaceName = devWorkspaceName; + containerTerminal = e2eContainer.get(CLASSES.ContainerTerminal); + 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.execInContainerCommand(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 92ee904d8c6..7a508ec91e9 100644 --- a/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts +++ b/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts @@ -1,74 +1,79 @@ -import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +/** ******************************************************************* + * 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 { ContainerTerminal, 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'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; -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: 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 ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, 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 = e2eContainer.get(CLASSES.KubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor.workspaceName = devWorkspaceName; + kubernetesCommandLineToolsExecutor.namespace = namespace; + containerTerminal = e2eContainer.get(CLASSES.ContainerTerminal); + }); - 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 ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, 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 workspace', function (): void { - kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); - }); + suiteTeardown('Delete workspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); }); - - diff --git a/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts.orig b/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts.orig new file mode 100644 index 00000000000..01aa4adfc12 --- /dev/null +++ b/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts.orig @@ -0,0 +1,111 @@ +/** ******************************************************************* + * 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 { ContainerTerminal, 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'; +<<<<<<< HEAD +import { APITestConstants } from '../../constants/APITestConstants'; +import { BaseTestConstants } from '../../constants/BaseTestConstants'; + +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; +======= +import { API_TEST_CONSTANTS } from '../../constants/API_TEST_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; + +suite('Empty workspace API test', function (): void { + // works only for root user + 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: ContainerTerminal; +>>>>>>> main + + const gitRepository: string = 'https://github.com/crw-qe/web-nodejs-sample'; + + suiteSetup(`Create empty workspace with OC client ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, 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 = e2eContainer.get(CLASSES.KubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor.workspaceName = devWorkspaceName; + kubernetesCommandLineToolsExecutor.namespace = namespace; + containerTerminal = e2eContainer.get(CLASSES.ContainerTerminal); + }); + + 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 ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, 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 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 + ); + }); + }); + +<<<<<<< HEAD + 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 workspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); +======= + suiteTeardown('Delete workspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); +>>>>>>> main +}); diff --git a/tests/e2e/specs/api/InbuiltApplicationDevWorkspacesAPI.spec.ts b/tests/e2e/specs/api/InbuiltApplicationDevWorkspacesAPI.spec.ts new file mode 100644 index 00000000000..abb8342971c --- /dev/null +++ b/tests/e2e/specs/api/InbuiltApplicationDevWorkspacesAPI.spec.ts @@ -0,0 +1,130 @@ +/** ******************************************************************* + * 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 { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigurationHelper'; +import { ShellString } from 'shelljs'; +import { expect } from 'chai'; +import { StringUtil } from '../../utils/StringUtil'; +import { DevfilesRegistryHelper } from '../../utils/DevfilesRegistryHelper'; +import { Logger } from '../../utils/Logger'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +import { API_TEST_CONSTANTS } from '../../constants/API_TEST_CONSTANTS'; +import { MOCHA_CONSTANTS } from '../../constants/MOCHA_CONSTANTS'; + +/** + * dynamically generating tests + * info: https://mochajs.org/#delayed-root-suite + */ + +void (async function (): Promise { + const devfilesRegistryHelper: DevfilesRegistryHelper = e2eContainer.get(CLASSES.DevfilesRegistryHelper); + let devfileSamples: any; + if (MOCHA_CONSTANTS.MOCHA_DELAYED_SUITE) { + devfileSamples = await devfilesRegistryHelper.collectPathsToDevfilesFromRegistry( + true, + API_TEST_CONSTANTS.TS_API_TEST_DEV_WORKSPACE_LIST?.split(',') + ); + } + + for (const devfileSample of devfileSamples) { + suite( + `Inbuilt DevWorkspaces test suite for "${devfileSample.name}" sample ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, + function (): void { + this.bail(false); + let devWorkspaceConfigurationHelper: DevWorkspaceConfigurationHelper; + let kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor; + let containerTerminal: ContainerTerminal; + let devfileContextYaml: any; + let devWorkspaceName: string | undefined; + let clonedProjectName: string; + let containerWorkDir: string; + const devfilesBuildCommands: any[] = []; + + test('Get DevWorkspace configuration', function (): void { + devWorkspaceConfigurationHelper = new DevWorkspaceConfigurationHelper({}); + devfileContextYaml = devWorkspaceConfigurationHelper.getDevWorkspaceConfigurationsAsYaml( + devfileSample.devWorkspaceConfigurationString + ); + devWorkspaceName = devfileContextYaml.DevWorkspace.metadata.name; + kubernetesCommandLineToolsExecutor = e2eContainer.get(CLASSES.KubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor.workspaceName = devWorkspaceName; + containerTerminal = e2eContainer.get(CLASSES.ContainerTerminal); + kubernetesCommandLineToolsExecutor.loginToOcp(); + }); + + test('Collect build commands from the devfile', function (): void { + if (devfileContextYaml.DevWorkspace.spec.template.commands === undefined) { + Logger.info('Devfile does not contains any commands.'); + } else { + devfileContextYaml.DevWorkspace.spec.template.commands.forEach((command: any): void => { + if (command.exec?.group?.kind === 'build') { + Logger.debug(`Build command found: ${command.exec.commandLine}`); + devfilesBuildCommands.push(command); + } + }); + } + }); + + test('Create and wait DevWorkspace', function (): void { + const output: ShellString = kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsStringOutput( + devfileSample.devWorkspaceConfigurationString + ); + expect(output.stdout) + .contains('devworkspacetemplate') + .and.contains('devworkspace') + .and.contains.oneOf(['created', 'configured']); + }); + + test('Wait until DevWorkspace has status "ready"', function (): void { + this.timeout(TIMEOUT_CONSTANTS.TS_SELENIUM_START_WORKSPACE_TIMEOUT); + expect(kubernetesCommandLineToolsExecutor.waitDevWorkspace().stdout).contains('condition met'); + }); + + test('Check if project was created', function (): void { + clonedProjectName = devfileContextYaml.DevWorkspace.spec.template.projects[0].name; + 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 { + this.test?.timeout(1500000); // 25 minutes because build of Quarkus sample takes 20+ minutes + 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.execInContainerCommand(commandString, command.exec.component); + expect(output.code).eqls(0); + }); + } + }); + + test('Delete DevWorkspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); + } + ); + } + + run(); +})(); diff --git a/tests/e2e/specs/api/PodOverridesAPI.spec.ts b/tests/e2e/specs/api/PodOverridesAPI.spec.ts index 10cdcb529d3..41c4e27733d 100644 --- a/tests/e2e/specs/api/PodOverridesAPI.spec.ts +++ b/tests/e2e/specs/api/PodOverridesAPI.spec.ts @@ -1,44 +1,59 @@ +/** ******************************************************************* + * 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 { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; -suite(`Test defining pod overrides via attribute.`, async function (): Promise { - const pathToSampleFile: string = path.resolve('resources/pod-overrides.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 ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, 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 = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + kubernetesCommandLineToolsExecutor.workspaceName = workspaceName; + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); + 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/Documentation.spec.ts b/tests/e2e/specs/dashboard-samples/Documentation.spec.ts new file mode 100644 index 00000000000..bf02990af6e --- /dev/null +++ b/tests/e2e/specs/dashboard-samples/Documentation.spec.ts @@ -0,0 +1,142 @@ +/** ******************************************************************* + * 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 { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { Workspaces } from '../../pageobjects/dashboard/Workspaces'; +import { ShellExecutor } from '../../utils/ShellExecutor'; +import { WorkspaceDetails } from '../../pageobjects/dashboard/workspace-details/WorkspaceDetails'; +import axios from 'axios'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { OAUTH_CONSTANTS } from '../../constants/OAUTH_CONSTANTS'; +import { Logger } from '../../utils/Logger'; + +// suit works for DevSpaces +suite(`Check links to documentation page in Dashboard ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + this.timeout(180000); + const pathToSampleFile: string = path.resolve('resources/default-devfile.yaml'); + const workspaceName: string = YAML.parse(fs.readFileSync(pathToSampleFile, 'utf8')).metadata.name; + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + kubernetesCommandLineToolsExecutor.workspaceName = workspaceName; + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + const workspaces: Workspaces = e2eContainer.get(CLASSES.Workspaces); + const workspaceDetails: WorkspaceDetails = e2eContainer.get(CLASSES.WorkspaceDetails); + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const majorMinorVersion: string = BASE_TEST_CONSTANTS.TESTING_APPLICATION_VERSION.split('.').slice(0, 2).join('.'); // extract major.minor version from full version + let parentGUID: string = ''; + let docs: any, links: any, productVersion: any; + let webSocketTroubleshooting: any, workspace: any, devfile: any, general: any, storageTypes: any; + + suiteSetup('Login into OC client and apply default DevFile', function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp(); + kubernetesCommandLineToolsExecutor.applyYamlConfigurationAsFile(pathToSampleFile); + shellExecutor.wait(5); + }); + + suiteSetup('Get links from product version github branch', function (): void { + try { + ({ docs, links, productVersion } = JSON.parse( + shellExecutor.curl( + `https://raw.githubusercontent.com/redhat-developer/devspaces-images/devspaces-${majorMinorVersion}-rhel-8/devspaces-dashboard/packages/dashboard-frontend/assets/branding/product.json` + ) + )); + } catch (e) { + Logger.error('Cannot fetch documentation links'); + throw e; + } + ({ webSocketTroubleshooting, workspace, devfile, general, storageTypes } = docs); + }); + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + + test('Check if product.json config contains correct application version', function (): void { + [productVersion, links[1].href, devfile, workspace, general, storageTypes, webSocketTroubleshooting].forEach((e): void => { + expect(e, 'Fetched links not matches with tested product version').contains(majorMinorVersion); + }); + }); + + test('Check if documentation section "About" present on Dashboard', async function (): Promise { + await dashboard.openAboutMenu(); + }); + + test('Check if documentation section "About" in top menu has required links', async function (): Promise { + parentGUID = await browserTabsUtil.getCurrentWindowHandle(); + for (const link of links) { + await dashboard.selectAboutMenuItem(link.text); + await browserTabsUtil.waitAndSwitchToAnotherWindow(parentGUID); + const currentUrl: string = await browserTabsUtil.getCurrentUrl(); + expect(link.href, `${link.href} not includes ${currentUrl}`).oneOf([currentUrl, currentUrl + '/']); + await browserTabsUtil.switchToWindow(parentGUID); + await browserTabsUtil.closeAllTabsExceptCurrent(); + } + }); + + test('Check if "About" dialog menu contains correct application version and username', async function (): Promise { + await dashboard.selectAboutMenuItem('About'); + await dashboard.waitAboutDialogWindowMenuElements(); + expect(await dashboard.getApplicationVersionFromAboutDialogWindow(), 'Wrong product version').eqls(productVersion); + expect(await dashboard.getUsernameFromAboutDialogWindow(), 'Wrong username').eqls(OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME); + await dashboard.closeAboutDialogWindow(); + }); + + test('Check if Workspaces page contains "Learn More" documentation link', async function (): Promise { + await dashboard.clickWorkspacesButton(); + await workspaces.waitPage(); + expect(await workspaces.getLearnMoreDocumentationLink(), '"Learn More" doc link is broken').eqls(workspace); + }); + + test('Check if Workspace Details page contains "Storage types" documentation link', async function (): Promise { + await workspaces.clickWorkspaceListItemLink(workspaceName); + await workspaceDetails.waitWorkspaceTitle(workspaceName); + await workspaceDetails.clickStorageTypeInfo(); + expect(await workspaceDetails.getOpenStorageTypeDocumentationLink(), '"Storage types" doc link is broken').eqls(storageTypes); + }); + + if (BASE_TEST_CONSTANTS.IS_PRODUCT_DOCUMENTATION_RELEASED) { + test('Check if product.json documentation links returns status code 200', async function (): Promise { + const documentationLinks: string[] = [devfile, workspace, general, storageTypes, webSocketTroubleshooting]; + links.forEach((link: any): void => { + documentationLinks.push(link.href); + }); + for (const e of documentationLinks) { + let responseData: any; + try { + responseData = await axios.get(e); + } catch (e) { + responseData = e; + } finally { + expect(responseData.status, `Wrong status code ${responseData.status}`).eqls(200); + } + } + }); + } + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Delete default DevWorkspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); +}); diff --git a/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts b/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts index fffc6807ca1..3aac7ba430d 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 @@ -9,52 +9,65 @@ **********************************************************************/ import { e2eContainer } from '../../configs/inversify.config'; import { ActivityBar, ViewControl, Workbench } from 'monaco-page-objects'; -import { CLASSES } from '../../configs/inversify.types'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; import { Logger } from '../../utils/Logger'; import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; import { LoginTests } from '../../tests-library/LoginTests'; import { registerRunningWorkspace } from '../MochaHooks'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; - -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; const stackName: string = 'Empty Workspace'; -suite(`${stackName} test`, async () => { - suite(`Create ${stackName} workspace`, async () => { - loginTests.loginIntoChe(); - workspaceHandlingTests.createAndOpenWorkspace(stackName); - workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - test('Register running workspace', async () => { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - test('Wait workspace readiness', async() => { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - - 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()}`); - } - }); - }); - - suite('Stopping and deleting the workspace', async () => { - 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(`${stackName} test ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + 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('Register running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + 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(); + + Logger.debug('Editor sections:'); + for (const control of activityBarControls) { + Logger.debug(`${await control.getTitle()}`); + } + }); + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); }); diff --git a/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts.orig b/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts.orig new file mode 100644 index 00000000000..d0d7df5e5fe --- /dev/null +++ b/tests/e2e/specs/dashboard-samples/EmptyWorkspace.spec.ts.orig @@ -0,0 +1,96 @@ +/** ******************************************************************* + * 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 { e2eContainer } from '../../configs/inversify.config'; +import { ActivityBar, ViewControl, Workbench } from 'monaco-page-objects'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { Logger } from '../../utils/Logger'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +<<<<<<< HEAD + +const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); +const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); +const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); +const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + +======= +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; + +>>>>>>> main +const stackName: string = 'Empty Workspace'; + +suite(`${stackName} test ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + 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(); + }); + +<<<<<<< HEAD + suite('Stopping and deleting the workspace', async () => { + 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('Register running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + 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(); + + Logger.debug('Editor sections:'); + for (const control of activityBarControls) { + Logger.debug(`${await control.getTitle()}`); + } + }); + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); +>>>>>>> main +}); diff --git a/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts b/tests/e2e/specs/dashboard-samples/Quarkus.spec.ts index 998f11da5e9..bdb682129bf 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 @@ -8,45 +8,78 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { SideBarView, ViewSection } from 'monaco-page-objects'; +import { 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 { Logger } from '../../utils/Logger'; - -const stackName: string = 'Java 11 with Quarkus'; -const projectName: string = 'quarkus-quickstarts'; -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); - -suite(`The ${stackName} userstory`, async function (): Promise { - let projectSection: ViewSection; - suite(`Create workspace from ${stackName} simple`, async function (): Promise { - loginTests.loginIntoChe(); - workspaceHandlingTests.createAndOpenWorkspace(stackName); - workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - test('Register running workspace', async () => { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - 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 the project files was imported', async function (): Promise { - const label: string = 'devfile.yaml'; - await projectSection.findItem(label); - Logger.debug(`projectSection.findItem: find ${label}`); - }); - test('Stopping and deleting the workspace', async function (): Promise { - await workspaceHandlingTests.stopAndRemoveWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - loginTests.logoutFromChe(); - }); +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { expect } from 'chai'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; + +const stackName: string = 'Quarkus REST API'; + +suite(`The ${stackName} userstory ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + + let projectSection: ViewSection; + const projectName: string = 'quarkus-quickstarts'; + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + + 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('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 { + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, projectName), 'Project folder was not imported').not.undefined; + }); + + test('Accept the project as a trusted one', async function (): Promise { + await projectAndFileTests.performTrustAuthorDialog(); + }); + + test('Check the project files was imported', async function (): Promise { + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME, 2), + 'Project files were not imported' + ).not.undefined; + }); + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); }); diff --git a/tests/e2e/specs/dashboard-samples/RecomendedExtentions.spec.ts.orig b/tests/e2e/specs/dashboard-samples/RecomendedExtentions.spec.ts.orig new file mode 100644 index 00000000000..779f9fb9ba8 --- /dev/null +++ b/tests/e2e/specs/dashboard-samples/RecomendedExtentions.spec.ts.orig @@ -0,0 +1,201 @@ +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { + 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'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { Logger } from '../../utils/Logger'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; +import { expect } from 'chai'; +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { PluginsTestConstants } from '../../constants/PluginsTestConstants'; +import { BaseTestConstants } from '../../constants/BaseTestConstants'; + +const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); +const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); +const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); +const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + +const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; +const samples: string[] = PluginsTestConstants.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) { + workspaceHandlingTests.createAndOpenWorkspace(sample); + 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(); +}); diff --git a/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts b/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts new file mode 100644 index 00000000000..71f5c6d8670 --- /dev/null +++ b/tests/e2e/specs/dashboard-samples/RecommendedExtensions.spec.ts @@ -0,0 +1,258 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { + ActivityBar, + EditorView, + ExtensionsViewItem, + ExtensionsViewSection, + Locators, + SideBarView, + TextEditor, + ViewSection +} from 'monaco-page-objects'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { Logger } from '../../utils/Logger'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; +import { expect } from 'chai'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { PLUGIN_TEST_CONSTANTS } from '../../constants/PLUGIN_TEST_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; + +const samples: string[] = PLUGIN_TEST_CONSTANTS.TS_SAMPLE_LIST.split(','); + +// get visible items from Extension view, transform this from array to sorted string and compares it with existed recommended extensions +async function getVisibleFilteredItemsAndCompareWithRecommended(recommendations: string[]): Promise { + const extensionsView: SideBarView | undefined = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); + const [marketplaceSection]: ExtensionsViewSection[] = (await extensionsView?.getContent().getSections()) as ExtensionsViewSection[]; + const sections: ViewSection[] | undefined = await extensionsView?.getContent().getSections(); + + // if we have a big recommender extension list it can be overlapped by other recommendations panel, + // in this case we need to collapse it for instance: it is actual for Quarkus example + if (sections !== undefined) { + for (let i: number = 0; i < sections.length; i++) { + const currentSection: ViewSection = sections[i]; + const isOtherRecommendedSectionPresent: boolean = (await currentSection.getTitle()) === 'Other Recommendations'; + const isOtherRecommendationExpanded: boolean = await sections[i].isExpanded(); + if (isOtherRecommendedSectionPresent && isOtherRecommendationExpanded) { + await currentSection.collapse(); + } + } + } + Logger.debug('marketplaceSection.getVisibleItems()'); + const allFoundRecommendedItems: ExtensionsViewItem[] = await marketplaceSection.getVisibleItems(); + const allFoundRecommendedAuthors: string[] = await Promise.all( + allFoundRecommendedItems.map(async (item: ExtensionsViewItem): Promise => await item.getAuthor()) + ); + + const allFoundAuthorsAsSortedString: string = allFoundRecommendedAuthors.sort().toString(); + const allPublisherNamesAsSorString: string = recommendations.sort().toString(); + return allFoundAuthorsAsSortedString === allPublisherNamesAsSorString; +} +// get visible items from Extension view, transform this from array to sorted string and compares it with existed installed extensions +async function getVisibleFilteredItemsAndCompareWithInstalled(recommendations: string[]): Promise { + const extensionsView: SideBarView | undefined = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); + const [marketplaceSection]: ExtensionsViewSection[] = (await extensionsView?.getContent().getSections()) as ExtensionsViewSection[]; + Logger.debug('marketplaceSection.getVisibleItems()'); + const allFoundRecommendedItems: ExtensionsViewItem[] = await marketplaceSection.getVisibleItems(); + const allFoundRecommendedAuthors: string[] = await Promise.all( + allFoundRecommendedItems.map(async (item: ExtensionsViewItem): Promise => await item.getAuthor()) + ); + + const allFoundAuthorsAsSortedString: string = allFoundRecommendedAuthors.sort().toString(); + const allPublisherNamesAsSortString: string = recommendations.sort().toString(); + // in some cases we can have installed not only recommended extensions with some samples (for example .Net) + return allFoundAuthorsAsSortedString.includes(allPublisherNamesAsSortString); +} +for (const sample of samples) { + suite(`Check if recommended extensions installed for ${sample} ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const cheCodeLocatorLoader: CheCodeLocatorLoader = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const webCheCodeLocators: Locators = cheCodeLocatorLoader.webCheCodeLocators; + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + let projectSection: ViewSection; + let extensionSection: ExtensionsViewSection; + let extensionsView: SideBarView | undefined; + let publisherNames: string[]; + + const [pathToExtensionsListFileName, extensionsListFileName]: string[] = ['.vscode', 'extensions.json']; + + let recommendedExtensions: any = { + recommendations: [] + }; + + let parsedRecommendations: Array<{ name: string; publisher: string }>; + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + + 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(); + expect(WorkspaceHandlingTests.getWorkspaceName(), 'Workspace name was not fetched from the loading page').not.undefined; + }); + + test('Registering the running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Wait workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + + test('Check the project files were imported', async function (): Promise { + // add TS_IDE_LOAD_TIMEOUT timeout for waiting for finishing animation of all IDE parts (Welcome parts. bottom widgets. etc.) + // using TS_IDE_LOAD_TIMEOUT easier than performing of finishing animation all elements + await driverHelper.wait(TIMEOUT_CONSTANTS.TS_IDE_LOAD_TIMEOUT); + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, pathToExtensionsListFileName), 'Files not imported').not + .undefined; + }); + + test('Accept the project as a trusted one', async function (): Promise { + await projectAndFileTests.performTrustAuthorDialog(); + }); + + test(`Get recommended extensions list from ${extensionsListFileName}`, async function (): Promise { + // sometimes the Trust Dialog does not appear as expected - as result we need to execute "projectAndFileTests.performManageWorkspaceTrustBox()" method. In this case. + try { + await (await projectAndFileTests.getProjectTreeItem(projectSection, pathToExtensionsListFileName))?.select(); + } catch (err) { + await projectAndFileTests.performManageWorkspaceTrustBox(); + await (await projectAndFileTests.getProjectTreeItem(projectSection, pathToExtensionsListFileName))?.select(); + } + await (await projectAndFileTests.getProjectTreeItem(projectSection, extensionsListFileName, 3))?.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().'); + parsedRecommendations = recommendedExtensions.recommendations.map((rec: string): { name: string; publisher: string } => { + const [publisher, name] = rec.split('.'); + return { publisher, name }; + }); + Logger.debug(`Recommended extension for this workspace:\n${JSON.stringify(parsedRecommendations)}.`); + + publisherNames = parsedRecommendations.map((rec: { name: string; publisher: string }): string => rec.publisher); + expect(parsedRecommendations, 'Recommendations not found').not.empty; + }); + + test('Open "Extensions" view section', async function (): Promise { + Logger.debug('ActivityBar().getViewControl("Extensions"))?.openView(): open Extensions view.'); + // sometimes the Trust Dialog does not appear as expected - as result we need to execute "projectAndFileTests.performManageWorkspaceTrustBox()" method. In this case. + try { + extensionsView = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); + } catch (err) { + await projectAndFileTests.performManageWorkspaceTrustBox(); + extensionsView = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); + } + expect(extensionsView, 'Can`t find Extension section').not.undefined; + }); + + test('Let extensions complete installation', async function (): Promise { + this.test?.retries(0); + Logger.debug( + `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 { + // timeout 15 seconds per extensions + this.timeout(TIMEOUT_CONSTANTS.TS_FIND_EXTENSION_TEST_TIMEOUT * parsedRecommendations.length); + 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[]; + expect(extensionSection, 'Can`t find Extension section').not.undefined; + await driverHelper.waitVisibility( + webCheCodeLocators.ExtensionsViewSection.itemTitle, + TIMEOUT_CONSTANTS.TS_EDITOR_TAB_INTERACTION_TIMEOUT + ); + + Logger.debug('extensionSection.findItem by @recommended filter'); + try { + await extensionSection.findItem('@recommended'); + } catch (err) { + await driverHelper.wait(TIMEOUT_CONSTANTS.TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT); + await extensionSection.findItem('@recommended'); + } + const isReloadRequired: boolean = await driverHelper.isVisible( + (webCheCodeLocators.ExtensionsViewSection as any).requireReloadButton + ); + Logger.debug(`Is extensions require reload the editor: ${isReloadRequired}`); + + if (isReloadRequired) { + Logger.debug('Refreshing the page..'); + await browserTabsUtil.refreshPage(); + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + await driverHelper.waitVisibility( + webCheCodeLocators.ActivityBar.viewContainer, + TIMEOUT_CONSTANTS.TS_EDITOR_TAB_INTERACTION_TIMEOUT + ); + Logger.debug('ActivityBar().getViewControl("Extensions"))?.openView(): reopen Extensions view.'); + extensionsView = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); + await driverHelper.waitVisibility( + webCheCodeLocators.ExtensionsViewSection.itemTitle, + TIMEOUT_CONSTANTS.TS_EDITOR_TAB_INTERACTION_TIMEOUT + ); + expect(extensionsView, 'Can`t find Extension View section').not.undefined; + [extensionSection] = (await extensionsView?.getContent().getSections()) as ExtensionsViewSection[]; + expect(extensionSection, 'Can`t find Extension section').not.undefined; + await extensionSection.findItem('@recommended '); + } + + Logger.debug('extensionSection.findItem by @recommended filter'); + expect(await getVisibleFilteredItemsAndCompareWithRecommended(publisherNames)).to.be.true; + Logger.debug(`All recommended extensions were found by @recommended filter: ---- ${publisherNames} ----`); + + Logger.debug('extensionSection.findItem by @installed filter'); + try { + await extensionSection.findItem('@installed '); + } catch (err) { + await driverHelper.wait(TIMEOUT_CONSTANTS.TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT); + await extensionSection.findItem('@installed '); + } + expect(await getVisibleFilteredItemsAndCompareWithInstalled(publisherNames)).to.be.true; + Logger.debug(`All recommended extensions were found by @installed filter: ---- ${publisherNames} ----`); + }); + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + }); +} diff --git a/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts index 574fb0376cf..856c1797d90 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 @@ -8,11 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { - SideBarView, - ViewItem, - ViewSection -} from 'monaco-page-objects'; +import { ViewSection } from 'monaco-page-objects'; import { registerRunningWorkspace } from '../MochaHooks'; import { LoginTests } from '../../tests-library/LoginTests'; import { e2eContainer } from '../../configs/inversify.config'; @@ -25,74 +21,104 @@ 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'; - -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const ocpMainPage: OcpMainPage = e2eContainer.get(CLASSES.OcpMainPage); -let ocpImportPage: OcpImportFromGitPage; -let ocpApplicationPage: OcpApplicationPage; -const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(); - -// works only with no-admin user -suite(`DevConsole Integration`, async function (): Promise { - // test specific data - const gitImportRepo: string = 'https://github.com/crw-qe/summit-lab-spring-music.git'; - const gitImportReference: string = 'pipeline'; - const projectLabel: string = 'app.openshift.io/runtime=spring'; - const projectName: string = 'devconsole-integration-test'; - - suiteSetup('Create new empty project using ocp', async function (): Promise { - kubernetesCommandLineToolsExecutor.loginToOcp(); - kubernetesCommandLineToolsExecutor.createProject(projectName); - }); - - loginTests.loginIntoOcpConsole(); - - test('Select test project 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('Fill and submit import data', async function (): Promise { - ocpApplicationPage = await ocpImportPage.fitAndSubmitConfiguration(gitImportRepo, gitImportReference, projectLabel); - }); - - test('Wait until application creates', async function (): Promise { - await ocpApplicationPage.waitApplicationIcon(); - }); - - test('Check if application has worked link "Open Source Code"', async function (): Promise { - await ocpApplicationPage.waitAndOpenEditSourceCodeIcon(); - }); - - loginTests.loginIntoChe(); - - workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - - test('Registering the running workspace', async function (): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); - - test('Check if application source code opens in workspace', async function (): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); - - test('Check if project and files imported', async function (): Promise { - const applicationSourceProjectName: string = 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); - }); - - loginTests.logoutFromChe(); - - suiteTeardown('Delete project using ocp', async function (): Promise { - kubernetesCommandLineToolsExecutor.deleteProject(projectName); - }); +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; + +suite(`DevConsole Integration ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + let ocpImportPage: OcpImportFromGitPage; + let ocpApplicationPage: OcpApplicationPage; + + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + 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 kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + // test specific data + const gitImportRepo: string = 'https://github.com/crw-qe/summit-lab-spring-music.git'; + const gitImportReference: string = 'pipeline'; + 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); + }); + + loginTests.loginIntoOcpConsole(); + + 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('Fill and submit import data', async function (): Promise { + ocpApplicationPage = await ocpImportPage.fitAndSubmitConfiguration(gitImportRepo, gitImportReference, projectLabel); + }); + + test('Wait until application creates', async function (): Promise { + await ocpApplicationPage.waitApplicationIcon(); + }); + + test('Check if application has worked link "Open Source Code"', async function (): Promise { + await ocpApplicationPage.waitAndOpenEditSourceCodeIcon(); + }); + + test('Login', async function (): Promise { + try { + await dashboard.waitLoader(TIMEOUT_CONSTANTS.TS_WAIT_LOADER_PRESENCE_TIMEOUT); + } catch (e) { + await loginTests.loginIntoChe(); + } + }); + + 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('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 projectAndFileTests.getProjectViewSession(); + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, applicationSourceProjectName), + 'Project folder was not imported' + ).not.undefined; + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME), + 'Project files were not imported' + ).not.undefined; + }); + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Delete project using ocp', function (): void { + kubernetesCommandLineToolsExecutor.workspaceName = + WorkspaceHandlingTests.getWorkspaceName() !== '' ? WorkspaceHandlingTests.getWorkspaceName() : 'spring-music'; + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + kubernetesCommandLineToolsExecutor.deleteProject(projectName); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); }); diff --git a/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts.orig b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts.orig new file mode 100644 index 00000000000..33b50fb478e --- /dev/null +++ b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts.orig @@ -0,0 +1,137 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { ViewSection } from 'monaco-page-objects'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { expect } from 'chai'; +import { OcpMainPage } from '../../pageobjects/openshift/OcpMainPage'; +import { OcpImportFromGitPage } from '../../pageobjects/openshift/OcpImportFromGitPage'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { StringUtil } from '../../utils/StringUtil'; +import { OcpApplicationPage } from '../../pageobjects/openshift/OcpApplicationPage'; +<<<<<<< HEAD +import { BaseTestConstants } from '../../constants/BaseTestConstants'; +======= +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +>>>>>>> main + +suite(`DevConsole Integration ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + let ocpImportPage: OcpImportFromGitPage; + let ocpApplicationPage: OcpApplicationPage; + + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + 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 kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + // test specific data + const gitImportRepo: string = 'https://github.com/crw-qe/summit-lab-spring-music.git'; + const gitImportReference: string = 'pipeline'; + 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); + }); + + loginTests.loginIntoOcpConsole(); + + 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('Fill and submit import data', async function (): Promise { + ocpApplicationPage = await ocpImportPage.fitAndSubmitConfiguration(gitImportRepo, gitImportReference, projectLabel); + }); + + test('Wait until application creates', async function (): Promise { + await ocpApplicationPage.waitApplicationIcon(); + }); + + test('Check if application has worked link "Open Source Code"', async function (): Promise { + await ocpApplicationPage.waitAndOpenEditSourceCodeIcon(); + }); + + test('Login', async function (): Promise { + try { + await dashboard.waitLoader(TIMEOUT_CONSTANTS.TS_WAIT_LOADER_PRESENCE_TIMEOUT); + } catch (e) { + await loginTests.loginIntoChe(); + } + }); + + 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('Check if application source code opens in workspace', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + +<<<<<<< HEAD + 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('Check if project and files imported', async function (): Promise { + const applicationSourceProjectName: string = StringUtil.getProjectNameFromGitUrl(gitImportRepo); + const projectSection: ViewSection = await projectAndFileTests.getProjectViewSession(); + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, applicationSourceProjectName), + 'Project folder was not imported' + ).not.undefined; + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME), + 'Project files were not imported' + ).not.undefined; + }); +>>>>>>> main + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Delete project using ocp', function (): void { + kubernetesCommandLineToolsExecutor.workspaceName = + WorkspaceHandlingTests.getWorkspaceName() !== '' ? WorkspaceHandlingTests.getWorkspaceName() : 'spring-music'; + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + kubernetesCommandLineToolsExecutor.deleteProject(projectName); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); +}); diff --git a/tests/e2e/specs/factory/Factory.spec.ts b/tests/e2e/specs/factory/Factory.spec.ts index 67a641b7753..a7bfbf7b57b 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,15 @@ 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, + NewScmView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewSection } from 'monaco-page-objects'; import { expect } from 'chai'; import { OauthPage } from '../../pageobjects/git-providers/OauthPage'; @@ -32,169 +29,184 @@ import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader import { registerRunningWorkspace } from '../MochaHooks'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; -import { CLASSES } from '../../configs/inversify.types'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; import { DriverHelper } from '../../utils/DriverHelper'; import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; import { Logger } from '../../utils/Logger'; import { LoginTests } from '../../tests-library/LoginTests'; -import { OAuthConstants } from '../../constants/OAuthConstants'; -import { BaseTestConstants } from '../../constants/BaseTestConstants'; -import { FactoryTestConstants } from '../../constants/FactoryTestConstants'; - -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); - -const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; - -suite(`Create a workspace via launching a factory from the ${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(); - }); - } - - 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(); -}); +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'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; + +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, + function (): void { + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const cheCodeLocatorLoader: CheCodeLocatorLoader = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const webCheCodeLocators: Locators = cheCodeLocatorLoader.webCheCodeLocators; + const oauthPage: OauthPage = e2eContainer.get(CLASSES.OauthPage); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + + 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 refreshButtonLabel: string = 'Refresh'; + const pushItemLabel: string = 'Push'; + let testRepoProjectName: string; + + suiteSetup('Login', async function (): Promise { + await 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 projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, testRepoProjectName), 'Project folder was not imported').not + .undefined; + }); + + test('Accept the project as a trusted one', async function (): Promise { + await projectAndFileTests.performTrustAuthorDialog(); + }); + + test('Check if the project files were imported', async function (): Promise { + const label: string = BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME; + expect(await projectAndFileTests.getProjectTreeItem(projectSection, label), 'Project files were not imported').not.undefined; + }); + + test('Make changes to the file', async function (): Promise { + Logger.debug(`projectSection.openItem: "${fileToChange}"`); + await projectSection.openItem(testRepoProjectName, 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.inputField); + [scmProvider, ...rest] = await scmView.getProviders(); + if (scmProvider === undefined) { + await projectAndFileTests.performManageWorkspaceTrustBox(); + [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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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 { + 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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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.Notification.action); + 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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(refreshButtonLabel)); + const isCommitButtonDisabled: string = await driverHelper.waitAndGetElementAttribute( + webCheCodeLocators.Notification.action, + 'aria-disabled' + ); + expect(isCommitButtonDisabled).to.equal('true'); + }); + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + // to avoid a possible creating workspace which is not appeared on Dashboard yet. TODO: implement a better solution. + await driverHelper.wait(30000); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + } +); diff --git a/tests/e2e/specs/factory/Factory.spec.ts.orig b/tests/e2e/specs/factory/Factory.spec.ts.orig new file mode 100644 index 00000000000..b81bd942bae --- /dev/null +++ b/tests/e2e/specs/factory/Factory.spec.ts.orig @@ -0,0 +1,288 @@ +/** ******************************************************************* + * copyright (c) 2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import 'reflect-metadata'; + +import { e2eContainer } from '../../configs/inversify.config'; +import { + ActivityBar, + ContextMenu, + EditorView, + Locators, + NewScmView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewSection +} from 'monaco-page-objects'; +import { expect } from 'chai'; +import { OauthPage } from '../../pageobjects/git-providers/OauthPage'; +import { StringUtil } from '../../utils/StringUtil'; +import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { Logger } from '../../utils/Logger'; +import { LoginTests } from '../../tests-library/LoginTests'; +<<<<<<< HEAD +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'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +>>>>>>> main + +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, + function (): void { + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const cheCodeLocatorLoader: CheCodeLocatorLoader = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const webCheCodeLocators: Locators = cheCodeLocatorLoader.webCheCodeLocators; + const oauthPage: OauthPage = e2eContainer.get(CLASSES.OauthPage); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let rest: SingleScmProvider[]; + let scmContextMenu: ContextMenu; + +<<<<<<< HEAD +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); +======= + // test specific data + const timeToRefresh: number = 1500; + const changesToCommit: string = new Date().getTime().toString(); + const fileToChange: string = 'Date.txt'; + const refreshButtonLabel: string = 'Refresh'; + const pushItemLabel: string = 'Push'; + let testRepoProjectName: string; +>>>>>>> main + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + test('Navigate to the factory URL', async function (): Promise { + await browserTabsUtil.navigateTo(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_URL()); + }); + +<<<<<<< HEAD + // 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(); + }); + } +======= + 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()); + }); +>>>>>>> main + + 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 projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, testRepoProjectName), 'Project folder was not imported').not + .undefined; + }); + + test('Accept the project as a trusted one', async function (): Promise { + await projectAndFileTests.performTrustAuthorDialog(); + }); + +<<<<<<< HEAD + 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('Check if the project files were imported', async function (): Promise { + const label: string = BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME; + expect(await projectAndFileTests.getProjectTreeItem(projectSection, label), 'Project files were not imported').not.undefined; + }); + + test('Make changes to the file', async function (): Promise { + Logger.debug(`projectSection.openItem: "${fileToChange}"`); + await projectSection.openItem(testRepoProjectName, 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); + }); +>>>>>>> main + + 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.inputField); + [scmProvider, ...rest] = await scmView.getProviders(); + if (scmProvider === undefined) { + await projectAndFileTests.performManageWorkspaceTrustBox(); + [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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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 { + 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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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.Notification.action); + 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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(refreshButtonLabel)); + const isCommitButtonDisabled: string = await driverHelper.waitAndGetElementAttribute( + webCheCodeLocators.Notification.action, + 'aria-disabled' + ); + expect(isCommitButtonDisabled).to.equal('true'); + }); + +<<<<<<< HEAD + 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); + }); +======= + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); +>>>>>>> main + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + // to avoid a possible creating workspace which is not appeared on Dashboard yet. TODO: implement a better solution. + await driverHelper.wait(30000); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + +<<<<<<< HEAD + 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(); +}); +======= + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + } +); +>>>>>>> main diff --git a/tests/e2e/specs/factory/FactoryWithGitRepoOptions.spec.ts b/tests/e2e/specs/factory/FactoryWithGitRepoOptions.spec.ts new file mode 100644 index 00000000000..b9de237d12a --- /dev/null +++ b/tests/e2e/specs/factory/FactoryWithGitRepoOptions.spec.ts @@ -0,0 +1,77 @@ +/** ******************************************************************* + * copyright (c) 2024 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 { ViewSection } from 'monaco-page-objects'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { CLASSES } from '../../configs/inversify.types'; +import { e2eContainer } from '../../configs/inversify.config'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { StringUtil } from '../../utils/StringUtil'; +import { FACTORY_TEST_CONSTANTS } from '../../constants/FACTORY_TEST_CONSTANTS'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { expect } from 'chai'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; + +suite(`The FactoryWithGitRepoOptions userstory ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const factoryUrl: string = + FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git'; + const expectedBranchName: string = FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH || 'main'; + let projectSection: ViewSection; + suite(`Create workspace from factory:${factoryUrl}`, function (): void { + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + test(`Create and open new workspace from factory:${factoryUrl}`, async function (): Promise { + await workspaceHandlingTests.createAndOpenWorkspaceFromGitRepository(factoryUrl, expectedBranchName); + }); + 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 projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, projectName), 'Project folder was not imported').not + .undefined; + }); + test('Check the project files was imported', async function (): Promise { + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME), + 'Project files were not imported' + ).not.undefined; + await projectAndFileTests.performTrustAuthorDialog(); + }); + test('Check expected branch name', async function (): Promise { + const branchName: string = await projectAndFileTests.getBranchName(); + + expect(branchName, 'Branch name error').equals(expectedBranchName); + }); + test('Stop the workspace by UI', async function (): Promise { + await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + test('Delete the workspace by UI', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + }); +}); diff --git a/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts index dca0d3edb8d..4ee2548cca3 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,260 +11,256 @@ 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, + InputBox, + Locators, + ModalDialog, + NewScmView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewSection } from 'monaco-page-objects'; import { expect } from 'chai'; import { StringUtil } from '../../utils/StringUtil'; import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; -import WebDriverError = error.WebDriverError; import { registerRunningWorkspace } from '../MochaHooks'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; -import { CLASSES } from '../../configs/inversify.types'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; import { DriverHelper } from '../../utils/DriverHelper'; import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; import { Workspaces } from '../../pageobjects/dashboard/Workspaces'; -import { TimeoutConstants } from '../../constants/TimeoutConstants'; 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 { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; -const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); -const workspaces: Workspaces = e2eContainer.get(CLASSES.Workspaces); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository without PAT/OAuth setup ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, + function (): void { + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const cheCodeLocatorLoader: CheCodeLocatorLoader = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const webCheCodeLocators: Locators = cheCodeLocatorLoader.webCheCodeLocators; + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + const workspaces: Workspaces = e2eContainer.get(CLASSES.Workspaces); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); -suite(`Create a workspace via launching a factory from the ${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository without OAuth setup`, async function (): Promise { + 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'; + suiteSetup('Login', async function (): Promise { + await 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 PAT/OAuth for ${isPrivateRepo} repo`, async function (): Promise { + await dashboard.waitLoader(); + const loaderAlert: string = await dashboard.getLoaderAlert(); + expect(loaderAlert).to.contain('Could not reach devfile at'); + }); - 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); + }); + } else { + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); - 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']); - }); + test('Registering the running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - 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('Wait the workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); - loginTests.logoutFromChe(); + test('Check if a project folder has been created', async function (): Promise { + testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL); + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, testRepoProjectName), 'Project folder was not imported') + .not.undefined; + }); - } else { - workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + test('Accept the project as a trusted one', async function (): Promise { + await projectAndFileTests.performTrustAuthorDialog(); + }); - test('Registering the running workspace', async function (): Promise { - registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + test('Check if the project files were imported', async function (): Promise { + expect(await projectAndFileTests.getProjectTreeItem(projectSection, label), 'Project files were not imported').not + .undefined; + }); - test('Wait the workspace readiness', async function (): Promise { - await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); - }); + test('Make changes to the file', async function (): Promise { + Logger.debug(`projectSection.openItem: "${fileToChange}"`); + await projectSection.openItem(testRepoProjectName, 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('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('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.inputField); + let rest: SingleScmProvider[]; + [scmProvider, ...rest] = await scmView.getProviders(); + if (scmProvider === undefined) { + await projectAndFileTests.performManageWorkspaceTrustBox(); + [scmProvider, ...rest] = await scmView.getProviders(); + } + Logger.debug(`scmView.getProviders: "${JSON.stringify(scmProvider)}, ${rest}"`); + }); - 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('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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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 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('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('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('Commit the changes', async function (): Promise { + 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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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('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('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 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); - }); + 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('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); - }); - - 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 driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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).to.be.true; + }); - test('Stop the workspace', async function (): Promise { - await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - await browserTabsUtil.closeAllTabsExceptCurrent(); - }); + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); - test('Delete the workspace', async function (): Promise { - await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + // to avoid a possible creating workspace which is not appeared on Dashboard yet. TODO: implement a better solution. + await driverHelper.wait(30000); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + } - loginTests.logoutFromChe(); - } -}); + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + } +); diff --git a/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts.orig b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts.orig new file mode 100644 index 00000000000..97ec0cfb8e8 --- /dev/null +++ b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts.orig @@ -0,0 +1,401 @@ +/** ******************************************************************* + * copyright (c) 2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import 'reflect-metadata'; +import { e2eContainer } from '../../configs/inversify.config'; +import { + ActivityBar, + ContextMenu, + EditorView, + InputBox, + Locators, + ModalDialog, + NewScmView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewSection +} from 'monaco-page-objects'; +import { expect } from 'chai'; +import { StringUtil } from '../../utils/StringUtil'; +import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +import { Workspaces } from '../../pageobjects/dashboard/Workspaces'; +<<<<<<< HEAD +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +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 { Logger } from '../../utils/Logger'; +import { LoginTests } from '../../tests-library/LoginTests'; +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 { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +>>>>>>> main + +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository without PAT/OAuth setup ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, + function (): void { + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const cheCodeLocatorLoader: CheCodeLocatorLoader = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const webCheCodeLocators: Locators = cheCodeLocatorLoader.webCheCodeLocators; + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + const workspaces: Workspaces = e2eContainer.get(CLASSES.Workspaces); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + +<<<<<<< HEAD +suite(`Create a workspace via launching a factory from the ${FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository without OAuth setup`, async function (): Promise { +======= + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let scmContextMenu: ContextMenu; +>>>>>>> main + + // 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'; + +<<<<<<< HEAD + // 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'; +======= + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); +>>>>>>> main + + 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()); + }); + +<<<<<<< HEAD + test(`Navigate to the ${isPrivateRepo} repository factory URL`, async function (): Promise { + await browserTabsUtil.navigateTo(FactoryTestConstants.TS_SELENIUM_FACTORY_URL()); + }); + + if (FactoryTestConstants.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 (FACTORY_TEST_CONSTANTS.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + test(`Check that workspace cannot be created without PAT/OAuth for ${isPrivateRepo} repo`, async function (): Promise { + await dashboard.waitLoader(); + const loaderAlert: string = await dashboard.getLoaderAlert(); + expect(loaderAlert).to.contain('Could not reach devfile at'); + }); + + 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); + }); + } else { + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); + + test('Registering the running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); +>>>>>>> main + + 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); + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, testRepoProjectName), 'Project folder was not imported') + .not.undefined; + }); + + test('Accept the project as a trusted one', async function (): Promise { + await projectAndFileTests.performTrustAuthorDialog(); + }); + + test('Check if the project files were imported', async function (): Promise { + expect(await projectAndFileTests.getProjectTreeItem(projectSection, label), 'Project files were not imported').not + .undefined; + }); + + test('Make changes to the file', async function (): Promise { + Logger.debug(`projectSection.openItem: "${fileToChange}"`); + await projectSection.openItem(testRepoProjectName, 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); + }); + +<<<<<<< HEAD + 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('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.inputField); + let rest: SingleScmProvider[]; + [scmProvider, ...rest] = await scmView.getProviders(); + if (scmProvider === undefined) { + await projectAndFileTests.performManageWorkspaceTrustBox(); + [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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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); + }); +>>>>>>> main + + 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 { + 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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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); + }); + + 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('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(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 driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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).to.be.true; + }); + +<<<<<<< HEAD + 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}; + 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); + }); + + 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('Delete the workspace', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + loginTests.logoutFromChe(); + } +}); +======= + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + // to avoid a possible creating workspace which is not appeared on Dashboard yet. TODO: implement a better solution. + await driverHelper.wait(30000); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + } + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + } +); +>>>>>>> main diff --git a/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts index acc28d91ae4..bf7499666ce 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,26 +11,21 @@ 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, + InputBox, + Locators, + NewScmView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewSection } from 'monaco-page-objects'; import { expect } from 'chai'; -import WebDriverError = error.WebDriverError; import { registerRunningWorkspace } from '../MochaHooks'; import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; -import { CLASSES } from '../../configs/inversify.types'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; @@ -38,223 +33,225 @@ 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 { 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 { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; -const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); -const webCheCodeLocators: Locators = new CheCodeLocatorLoader().webCheCodeLocators; -const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository and deny the access ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, + function (): void { + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const cheCodeLocatorLoader: CheCodeLocatorLoader = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const webCheCodeLocators: Locators = cheCodeLocatorLoader.webCheCodeLocators; + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const oauthPage: OauthPage = e2eContainer.get(CLASSES.OauthPage); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); -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); + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let rest: SingleScmProvider[]; + let scmContextMenu: ContextMenu; - 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'; + 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 - 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'; + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); - loginTests.loginIntoChe(); + 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()); - }); + 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(); + }); - 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(); - }); - } + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); - 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', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); - test('Registering the running workspace', async function (): Promise { - 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(); - }); + if (FACTORY_TEST_CONSTANTS.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + test('Check that a project folder has not been cloned', async function (): Promise { + testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL); + await driverHelper.waitVisibility(webCheCodeLocators.TitleBar.itemElement); + await projectAndFileTests.performTrustAuthorDialog(); + const isProjectFolderUnable: string = await driverHelper.waitAndGetElementAttribute( + (webCheCodeLocators.TreeItem as any).projectFolderItem, + 'aria-label' + ); + expect(isProjectFolderUnable).to.contain('No Folder Opened Section'); + }); + } else { + test('Check if a project folder has been created', async function (): Promise { + testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL); + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, testRepoProjectName), 'Project folder was not imported') + .not.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('Accept the project as a trusted one', async function (): Promise { + await projectAndFileTests.performTrustAuthorDialog(); + }); - 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('Check if the project files were imported', async function (): Promise { + expect(await projectAndFileTests.getProjectTreeItem(projectSection, label), 'Project files were not imported').not + .undefined; + }); - 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'); - }); + test('Make changes to the file', async function (): Promise { + Logger.debug(`projectSection.openItem: "${fileToChange}"`); + await projectSection.openItem(testRepoProjectName, 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('Check that project files were not imported', async function (): Promise { - const isFileImported: ViewItem | undefined = await projectSection.findItem(label); - expect(isFileImported).eqls(undefined); - }); + 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.inputField); + [scmProvider, ...rest] = await scmView.getProviders(); + if (scmProvider === undefined) { + await projectAndFileTests.performManageWorkspaceTrustBox(); + [scmProvider, ...rest] = await scmView.getProviders(); + } + Logger.debug(`scmView.getProviders: "${JSON.stringify(scmProvider)}, ${rest}"`); + }); - } 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('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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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 { + 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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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'); - }); - - 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('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).to.be.true; + }); + } - test('Stop the workspace', async function (): Promise { - await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - await browserTabsUtil.closeAllTabsExceptCurrent(); - }); + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); - test('Delete the workspace', async function (): Promise { - await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); - }); + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + // to avoid a possible creating workspace which is not appeared on Dashboard yet. TODO: implement a better solution. + await driverHelper.wait(30000); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); - loginTests.logoutFromChe(); -}); + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + } +); diff --git a/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts.orig b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts.orig new file mode 100644 index 00000000000..62c634aa1b0 --- /dev/null +++ b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts.orig @@ -0,0 +1,389 @@ +/** ******************************************************************* + * copyright (c) 2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import 'reflect-metadata'; +import { e2eContainer } from '../../configs/inversify.config'; +import { + ActivityBar, + ContextMenu, + EditorView, + InputBox, + Locators, + NewScmView, + SingleScmProvider, + TextEditor, + ViewControl, + ViewSection +} from 'monaco-page-objects'; +import { expect } from 'chai'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { OauthPage } from '../../pageobjects/git-providers/OauthPage'; +import { StringUtil } from '../../utils/StringUtil'; +import { Logger } from '../../utils/Logger'; +import { LoginTests } from '../../tests-library/LoginTests'; +<<<<<<< HEAD +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 { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +>>>>>>> main + +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER} repository and deny the access ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, + function (): void { + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const cheCodeLocatorLoader: CheCodeLocatorLoader = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const webCheCodeLocators: Locators = cheCodeLocatorLoader.webCheCodeLocators; + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const oauthPage: OauthPage = e2eContainer.get(CLASSES.OauthPage); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + +<<<<<<< HEAD +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); +======= + let projectSection: ViewSection; + let scmProvider: SingleScmProvider; + let rest: SingleScmProvider[]; + let scmContextMenu: ContextMenu; +>>>>>>> main + + // 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'; + +<<<<<<< HEAD + // 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'; +======= + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); +>>>>>>> main + + test(`Navigate to the ${isPrivateRepo} repository factory URL`, async function (): Promise { + await browserTabsUtil.navigateTo(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_URL()); + }); + +<<<<<<< HEAD + test(`Navigate to the ${isPrivateRepo} repository 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 and deny access`, async function (): Promise { + await oauthPage.login(); + await oauthPage.waitOauthPage(); + await oauthPage.denyAccess(); + }); + } +======= + 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(); + }); +>>>>>>> main + + 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', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Wait the workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + + if (FACTORY_TEST_CONSTANTS.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO) { + test('Check that a project folder has not been cloned', async function (): Promise { + testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL); + await driverHelper.waitVisibility(webCheCodeLocators.TitleBar.itemElement); + await projectAndFileTests.performTrustAuthorDialog(); + const isProjectFolderUnable: string = await driverHelper.waitAndGetElementAttribute( + (webCheCodeLocators.TreeItem as any).projectFolderItem, + 'aria-label' + ); + expect(isProjectFolderUnable).to.contain('No Folder Opened Section'); + }); + } else { + test('Check if a project folder has been created', async function (): Promise { + testRepoProjectName = StringUtil.getProjectNameFromGitUrl(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL); + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, testRepoProjectName), 'Project folder was not imported') + .not.undefined; + }); + +<<<<<<< HEAD + 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('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); + } + } + }); + + 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'); + }); +======= + test('Accept the project as a trusted one', async function (): Promise { + await projectAndFileTests.performTrustAuthorDialog(); + }); + + test('Check if the project files were imported', async function (): Promise { + expect(await projectAndFileTests.getProjectTreeItem(projectSection, label), 'Project files were not imported').not + .undefined; + }); + + test('Make changes to the file', async function (): Promise { + Logger.debug(`projectSection.openItem: "${fileToChange}"`); + await projectSection.openItem(testRepoProjectName, 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); + }); +>>>>>>> main + + 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.inputField); + [scmProvider, ...rest] = await scmView.getProviders(); + if (scmProvider === undefined) { + await projectAndFileTests.performManageWorkspaceTrustBox(); + [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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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 { + 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(`wait and click on: "${refreshButtonLabel}"`); + await driverHelper.waitAndClick(webCheCodeLocators.ScmView.actionConstructor(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('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(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).to.be.true; + }); + } + +<<<<<<< HEAD + 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}; + 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); + }); + + 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('Delete the workspace', async function (): Promise { + await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + loginTests.logoutFromChe(); +}); +======= + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + // to avoid a possible creating workspace which is not appeared on Dashboard yet. TODO: implement a better solution. + await driverHelper.wait(30000); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + } +); +>>>>>>> main diff --git a/tests/e2e/specs/miscellaneous/CreateWorkspaceWithExistedName.spec.ts b/tests/e2e/specs/miscellaneous/CreateWorkspaceWithExistedName.spec.ts new file mode 100644 index 00000000000..22d657125ae --- /dev/null +++ b/tests/e2e/specs/miscellaneous/CreateWorkspaceWithExistedName.spec.ts @@ -0,0 +1,97 @@ +/** ******************************************************************* + * 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 { e2eContainer } from '../../configs/inversify.config'; +import { ViewSection } from 'monaco-page-objects'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { expect } from 'chai'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +import { FACTORY_TEST_CONSTANTS } from '../../constants/FACTORY_TEST_CONSTANTS'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; + +const stackName: string = BASE_TEST_CONSTANTS.TS_SELENIUM_DASHBOARD_SAMPLE_NAME || 'Python'; +const projectName: string = FACTORY_TEST_CONSTANTS.TS_SELENIUM_PROJECT_NAME || 'python-hello-world'; + +suite(`"Start workspace with existed workspace name" test ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + + let projectSection: ViewSection; + let existedWorkspaceName: string; + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + + test(`Create and open new workspace, stack:${stackName}`, async function (): Promise { + await workspaceHandlingTests.createAndOpenWorkspace(stackName); + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Wait workspace readiness and project folder has been created', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, projectName), 'Project folder was not imported').not.undefined; + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME), + 'Project files were not imported' + ).not.undefined; + }); + + test('Stop created workspace', async function (): Promise { + existedWorkspaceName = WorkspaceHandlingTests.getWorkspaceName(); + await workspaceHandlingTests.stopWorkspace(existedWorkspaceName); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + test(`Create new workspace from the same ${stackName} stack`, async function (): Promise { + existedWorkspaceName = WorkspaceHandlingTests.getWorkspaceName(); + + await browserTabsUtil.navigateTo(BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL); + await dashboard.waitPage(); + await workspaceHandlingTests.createAndOpenWorkspaceWithExistedWorkspaceName(stackName); + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Wait the second workspace readiness and project folder has been created', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, projectName), 'Project folder was not imported').not.undefined; + expect( + await projectAndFileTests.getProjectTreeItem(projectSection, BASE_TEST_CONSTANTS.TS_SELENIUM_PROJECT_ROOT_FILE_NAME), + 'Project files were not imported' + ).not.undefined; + }); + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown(`Stop and delete all created ${stackName} workspaces by API`, async function (): Promise { + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(existedWorkspaceName); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); +}); diff --git a/tests/e2e/specs/miscellaneous/CustomOpenVSXRegistry.spec.ts b/tests/e2e/specs/miscellaneous/CustomOpenVSXRegistry.spec.ts new file mode 100644 index 00000000000..f90f1d4ad9c --- /dev/null +++ b/tests/e2e/specs/miscellaneous/CustomOpenVSXRegistry.spec.ts @@ -0,0 +1,226 @@ +/** ******************************************************************* + * 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 { FACTORY_TEST_CONSTANTS } from '../../constants/FACTORY_TEST_CONSTANTS'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { ActivityBar, SideBarView, ViewItem, ViewSection } from 'monaco-page-objects'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { Logger } from '../../utils/Logger'; +import { expect } from 'chai'; +import { ShellString } from 'shelljs'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { error } from 'selenium-webdriver'; + +suite( + `Create a workspace via launching a factory from the ${FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL} repository`, + function (): void { + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const pathToPluginRegistry: string = '/projects/devspaces/dependencies/che-plugin-registry/'; + const internalRegistry: string = 'image-registry.openshift-image-registry.svc:5000'; + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const viewItems: ViewItem[] | undefined = []; + const testRepoProjectName: string = 'devspaces'; + const appVersion: string = BASE_TEST_CONSTANTS.TESTING_APPLICATION_VERSION + ? BASE_TEST_CONSTANTS.TESTING_APPLICATION_VERSION.split('.').slice(0, 2).join('.') + : 'next'; + let currentNamespace: string | undefined = ''; + let cheClusterNamespace: string | undefined = ''; + let cheClusterName: string | undefined = ''; + let projectSection: ViewSection; + let kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor; + let workspaceName: string = ''; + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + + test('Navigate to the factory URL', async function (): Promise { + await browserTabsUtil.navigateTo( + FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_URL() || 'https://github.com/redhat-developer/devspaces/' + ); + }); + + test('Obtain workspace name from workspace loader page', async function (): Promise { + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + workspaceName = WorkspaceHandlingTests.getWorkspaceName(); + expect(workspaceName, 'Workspace name was not fetched from the loading page').not.undefined; + }); + + 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 { + Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, testRepoProjectName), 'Project folder was not imported').not + .undefined; + }); + test('Accept the project as a trusted one', async function (): Promise { + await projectAndFileTests.performTrustAuthorDialog(); + }); + test('Remove VSX plugins and set redhat.vscode-xml', function (): void { + // modify the openvsx-sync.json file with just one item - for speeding up the build an image + kubernetesCommandLineToolsExecutor = e2eContainer.get(CLASSES.KubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor.workspaceName = workspaceName; + kubernetesCommandLineToolsExecutor.loginToOcp('admin'); + kubernetesCommandLineToolsExecutor.getPodAndContainerNames(); + const pathToOpenVSXOriginFile: string = `${pathToPluginRegistry}openvsx-sync.json`; + const pathToOpenVSXTmpFile: string = `${pathToPluginRegistry}temp.json`; + const editVSCListCommand: string = `jq "[.[] | select(.id == \\"redhat.vscode-xml\\")]" ${pathToOpenVSXOriginFile} > ${pathToOpenVSXTmpFile} && mv ${pathToOpenVSXTmpFile} ${pathToOpenVSXOriginFile}`; + const output: ShellString = kubernetesCommandLineToolsExecutor.execInContainerCommand(editVSCListCommand); + expect(output.code).to.equals(0); + const getCheClusterNamespaceCommand: string = 'oc get checluster --all-namespaces -o json | jq -r ".items[0].metadata.name"'; + const getCheClusterNameSpace: string = 'oc get checluster --all-namespaces -o json | jq -r ".items[0].metadata.namespace"'; + + // get che cluster name and namespace and init variables + cheClusterName = kubernetesCommandLineToolsExecutor.execInContainerCommand(getCheClusterNamespaceCommand).replace('\n', ''); + cheClusterNamespace = kubernetesCommandLineToolsExecutor.execInContainerCommand(getCheClusterNameSpace).replace('\n', ''); + }); + + test('Login podman into official registry', function (): void { + const commandToAuthenticateInRegistry: string = `podman login -u \"${process.env.REGISTRY_LOGIN}\" -p ${process.env.REGISTRY_PASSWORD} registry.redhat.io`; + const output: ShellString = kubernetesCommandLineToolsExecutor.execInContainerCommand(commandToAuthenticateInRegistry); + expect(output).contains('Login Succeeded!'); + }); + + test('Build and push custom image', function (): void { + currentNamespace = kubernetesCommandLineToolsExecutor.namespace; + const podmanPushCommand: string = `podman push ${internalRegistry}/${currentNamespace}/che-plugin-registry:${appVersion}`; + const commandToBuildCustomVSXImage: string = `cd ${pathToPluginRegistry} && yes | ./build.sh`; + const commandLoginIntoInternalRegistry: string = + 'podman login -u $(oc whoami | tr -d :) -p $(oc whoami -t) image-registry.openshift-image-registry.svc:5000'; + const retagImageCommand: string = `podman tag quay.io/devspaces/pluginregistry-rhel8:next ${internalRegistry}/${currentNamespace}/che-plugin-registry:${appVersion}`; + + const output: ShellString = kubernetesCommandLineToolsExecutor.execInContainerCommand(commandToBuildCustomVSXImage); + expect(output.code).equals(0); + + const outputRetagCommand: ShellString = kubernetesCommandLineToolsExecutor.execInContainerCommand(retagImageCommand); + expect(outputRetagCommand.code).equals(0); + + const loginIntoInternalRegistryOutput: ShellString = + kubernetesCommandLineToolsExecutor.execInContainerCommand(commandLoginIntoInternalRegistry); + expect(loginIntoInternalRegistryOutput).contains('Login Succeeded!'); + + const outputPushCommand: ShellString = kubernetesCommandLineToolsExecutor.execInContainerCommand(podmanPushCommand); + expect(outputPushCommand.code).equals(0); + }); + + test('Configure Che to use the embedded Eclipse Open VSX server', function (): void { + // create secret for using internal registry + const createRegistrySecretCommand: string = `oc create secret -n ${cheClusterNamespace} docker-registry regcred --docker-server=${internalRegistry} --docker-username=\$(oc whoami | tr -d :) --docker-password=\$(oc whoami -t)`; + const createSecretOutput: string = kubernetesCommandLineToolsExecutor.execInContainerCommand(createRegistrySecretCommand); + expect(createSecretOutput).contains('regcred created'); + + // add secret to service account + const patchPart: string = '{\\"imagePullSecrets\\": [{\\"name\\": \\"regcred\\"}]}'; + const addSecretToServiceAccountCommand: string = `oc patch serviceaccount default -n ${cheClusterNamespace} -p "${patchPart}"`; + const addSecretOutput: string = kubernetesCommandLineToolsExecutor.execInContainerCommand(addSecretToServiceAccountCommand); + expect(addSecretOutput).contains('default patched'); + + // patch che cluster with custom plugin registry + const patchVSXRegistryCommand: string = `cd ${pathToPluginRegistry} && ./patch-cluster.sh ${internalRegistry}/${currentNamespace}/che-plugin-registry:${appVersion}`; + const patchVSXOutput: string = kubernetesCommandLineToolsExecutor.execInContainerCommand(patchVSXRegistryCommand); + expect(patchVSXOutput).contains('Patched CheCluster '); + + // wait for deployment readiness after patching CHE cluster + const waitDeploymentReadiness: string = `oc rollout status deployment plugin-registry -n ${cheClusterNamespace} --timeout=120s`; + const waitDeploymentOutput: string = kubernetesCommandLineToolsExecutor.execInContainerCommand(waitDeploymentReadiness); + expect(waitDeploymentOutput).contains('successfully rolled out'); + }); + + test('Recreate workspace and check VSX custom plugin ', async function (): Promise { + await testWorkspaceUtil.deleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + registerRunningWorkspace(''); + await browserTabsUtil.navigateTo(FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_URL()); + }); + test('Registering the running workspace', function (): void { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Check Custom VSX plugin', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); + projectSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, testRepoProjectName), 'Project folder was not imported').not + .undefined; + await projectAndFileTests.performTrustAuthorDialog(); + const extensionsView: SideBarView | undefined = await (await new ActivityBar().getViewControl('Extensions'))?.openView(); + await driverHelper.wait(TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT); + const sections: ViewSection[] | undefined = await extensionsView?.getContent().getSections(); + if (sections !== undefined) { + for (const section of sections) { + let currentItem: ViewItem[] = []; + // sometimes the item (not related with custom VSX) can be empty or not extended, but it is not an error for the test + // we do not need to control none VSX items + try { + currentItem = await section.getVisibleItems(); + } catch (err) { + if (err instanceof error.ElementNotInteractableError) { + Logger.error('Current item is not interactable but test will continue'); + } else { + throw err; + } + } + if (currentItem.length > 0) { + viewItems?.push(...currentItem); + } + } + } + expect(viewItems.length).equals(1); + expect(await viewItems[0].getText()).contains('XML Language Support by Red Hat'); + }); + + suiteTeardown('Clean up resources and restore default CHE cluster CR', async function (): Promise { + try { + kubernetesCommandLineToolsExecutor.execInContainerCommand(`oc delete secret regcred -n ${cheClusterNamespace}`); + } catch (error) { + Logger.error(`Error during deleting the secret: ${error}`); + } + try { + const patch: string = '[{"op": "remove", "path": "/imagePullSecrets", "value": {"name": "regcred"}}]'; + const commandForRestoreServiceAccount: string = `oc patch serviceaccount default -n ${cheClusterNamespace} --type=json -p="${patch}"`; + kubernetesCommandLineToolsExecutor.execInContainerCommand(commandForRestoreServiceAccount); + } catch (error) { + Logger.error(`Error during restoring the service account: ${error}`); + } + try { + const patchDeployment: string = '[{"op": "remove", "path": "/spec/components/pluginRegistry/deployment"}]'; + const patchPluginRegistry: string = '[{"op": "remove", "path": "/spec/components/pluginRegistry/openVSXURL"}]'; + const restoreDefaultDeploymentPluginRegistry: string = `oc patch checluster ${cheClusterName} --type=json -p="${patchDeployment}" -n ${cheClusterNamespace}`; + const restoreOpenVSXRegistry: string = `oc patch checluster ${cheClusterName} --type=json -p="${patchPluginRegistry}" -n ${cheClusterNamespace}`; + kubernetesCommandLineToolsExecutor.execInContainerCommand(restoreDefaultDeploymentPluginRegistry); + kubernetesCommandLineToolsExecutor.execInContainerCommand(restoreOpenVSXRegistry); + } catch (error) { + Logger.error(`Error during restoring the VSX registry: ${error}`); + } + try { + await testWorkspaceUtil.deleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + } catch (error) { + Logger.error(`Cannot delete the workspace by API deleting the workspace: ${error}`); + } + }); + } +); diff --git a/tests/e2e/specs/miscellaneous/KubedockPodmanTest.spec.ts b/tests/e2e/specs/miscellaneous/KubedockPodmanTest.spec.ts new file mode 100644 index 00000000000..ecfd0d4400d --- /dev/null +++ b/tests/e2e/specs/miscellaneous/KubedockPodmanTest.spec.ts @@ -0,0 +1,122 @@ +/** ******************************************************************* + * 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 { ViewSection } from 'monaco-page-objects'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { e2eContainer } from '../../configs/inversify.config'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { expect } from 'chai'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ShellString } from 'shelljs'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; + +suite( + `Check possibility to manage containers within a workspace with kubedock and podman ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, + function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + + let kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor; + let workspaceName: string = ''; + + const testScript: string = + '# Enable Kubedock\n' + + 'export KUBEDOCK_ENABLED=true\n' + + 'echo KUBEDOCK_ENABLED\n' + + '/entrypoint.sh\n' + + 'cd $PROJECT_SOURCE\n' + + 'export ARCH=$(uname -m)\n' + + 'export DATE=$(date +"%m%d%y")\n' + + 'export USER=$(oc whoami)\n' + + 'export TKN=$(oc whoami -t)\n' + + 'export REG="image-registry.openshift-image-registry.svc:5000"\n' + + 'export PROJECT=$(oc project -q)\n' + + 'export IMG="${REG}/${PROJECT}/hello:${DATE}"\n' + + 'podman login --tls-verify=false --username ${USER} --password ${TKN} ${REG}\n' + + 'podman build -t ${IMG} -f Dockerfile.${ARCH}\n' + + 'podman push --tls-verify=false ${IMG}\n'; + + const runTestScript: string = + '# Enable Kubedock\n' + + 'export KUBEDOCK_ENABLED=true\n' + + 'echo KUBEDOCK_ENABLED\n' + + '/entrypoint.sh\n' + + 'export DATE=$(date +"%m%d%y")\n' + + 'export USER=$(oc whoami)\n' + + 'export TKN=$(oc whoami -t)\n' + + 'export REG="image-registry.openshift-image-registry.svc:5000"\n' + + 'export PROJECT=$(oc project -q)\n' + + 'export IMG="${REG}/${PROJECT}/hello:${DATE}"\n' + + 'podman login --tls-verify=false --username ${USER} --password ${TKN} ${REG}\n' + + 'podman run --rm ${IMG}'; + + const factoryUrl: string = 'https://github.com/crw-qe/dockerfile-hello-world'; + + suiteSetup('Login', async function (): Promise { + await 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(); + workspaceName = WorkspaceHandlingTests.getWorkspaceName(); + expect(workspaceName, 'Workspace name was not fetched from the loading page').not.undefined; + }); + + test('Register running workspace', function (): void { + registerRunningWorkspace(workspaceName); + }); + + test('Wait workspace readiness', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + + test('Check the project files were imported', async function (): Promise { + const projectSection: ViewSection = await projectAndFileTests.getProjectViewSession(); + expect(await projectAndFileTests.getProjectTreeItem(projectSection, 'Dockerfile.ppc64le'), 'Files not imported').not.undefined; + }); + + test('Create and check container runs using kubedock and podman', function (): void { + kubernetesCommandLineToolsExecutor = e2eContainer.get(CLASSES.KubernetesCommandLineToolsExecutor); + kubernetesCommandLineToolsExecutor.workspaceName = workspaceName; + kubernetesCommandLineToolsExecutor.loginToOcp(); + kubernetesCommandLineToolsExecutor.getPodAndContainerNames(); + const output: ShellString = kubernetesCommandLineToolsExecutor.execInContainerCommand(testScript); + expect(output, 'Podman test script failed').contains('Successfully tagged'); + const runOutput: ShellString = kubernetesCommandLineToolsExecutor.execInContainerCommand(runTestScript); + expect(runOutput, 'Podman test script failed').contains('Hello from Kubedock!'); + }); + + suiteTeardown('Open dashboard and close all other tabs', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); + } +); diff --git a/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts b/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts index eb459aa787c..bccb16dad7c 100644 --- a/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts +++ b/tests/e2e/specs/miscellaneous/PredefinedNamespace.spec.ts @@ -1,74 +1,99 @@ +/** ******************************************************************* + * 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 { expect } from 'chai'; import { CLASSES } from '../../configs/inversify.types'; import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; import { Logger } from '../../utils/Logger'; -import { LoginTests } from '../../tests-library/LoginTests'; -import { registerRunningWorkspace } from '../MochaHooks'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ShellExecutor } from '../../utils/ShellExecutor'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigurationHelper'; +import { DevfileContext } from '@eclipse-che/che-devworkspace-generator/lib/api/devfile-context'; -const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); -const util: any = require('node:util'); -const exec: any = util.promisify(require('node:child_process').exec); -const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); -const predefinedNamespaceName: string = 'predefined-ns'; +suite(`Create predefined workspace and check it ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const predefinedNamespaceName: string = 'predefined-ns'; + const workspaceName: string = 'empty-ws'; + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); + const userName: string = 'user'; + let devWorkspaceConfigurationHelper: DevWorkspaceConfigurationHelper; + let devfileContext: DevfileContext; + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); -async function runShellScript(shellCommandToExecution: string): Promise { - const {stdout, stderr} = await exec(shellCommandToExecution); - console.log(stdout); - console.error(stderr); - return stdout; -} + suiteSetup(function (): void { + // create a predefined namespace for user using shell script and login into user dashboard + Logger.debug('Test prerequisites:'); + Logger.debug( + ' (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.debug(' (2) "oc" client installed and logged into test OCP cluster with admin rights.'); + kubernetesCommandLineToolsExecutor.loginToOcp('admin'); + const predefinedProjectConfiguration: string = + 'kind: Namespace\n' + + 'apiVersion: v1\n' + + 'metadata:\n' + + ` name: ${predefinedNamespaceName}\n` + + ' labels:\n' + + ' app.kubernetes.io/part-of: che.eclipse.org\n' + + ' app.kubernetes.io/component: workspaces-namespace\n' + + ' annotations:\n' + + ' che.eclipse.org/username: user'; + kubernetesCommandLineToolsExecutor.applyWithoutNamespace(predefinedProjectConfiguration); + const setEditRightsForUser: string = `oc adm policy add-role-to-user edit user -n ${predefinedNamespaceName}`; + shellExecutor.executeCommand(setEditRightsForUser); + }); + // generate empty workspace DevFile and create it through oc client under a regular user + suiteSetup('Login', async function (): Promise { + const devfileContent: string = 'schemaVersion: 2.2.0\n' + 'metadata:\n' + ` name: ${workspaceName}\n`; + kubernetesCommandLineToolsExecutor.loginToOcp(userName); + devWorkspaceConfigurationHelper = new DevWorkspaceConfigurationHelper({ + devfileContent + }); + devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext(); + const devWorkspaceConfigurationYamlString: string = + devWorkspaceConfigurationHelper.getDevWorkspaceConfigurationYamlAsString(devfileContext); + kubernetesCommandLineToolsExecutor.applyWithoutNamespace(devWorkspaceConfigurationYamlString); + }); -suite(`Create predefined workspace and check it `, async function (): Promise { - let workspaceName: string = ''; + // verify that just created workspace is available for the dedicated user + test('Validate that predefined namespace has been created', function (): void { + const expectedProject: string = shellExecutor.executeArbitraryShellScript('oc get projects'); + expect(expectedProject).contains(predefinedNamespaceName); + }); - 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.'); + // ensure the generated DevSpace is created within the predefined namespace + test('Create test DevWorkspace and verify its creation within the predefined namespace', function (): void { + kubernetesCommandLineToolsExecutor.namespace = predefinedNamespaceName; + kubernetesCommandLineToolsExecutor.workspaceName = workspaceName; + // relogin under the admin user (because regular user does not have permissions for getting pod states) + kubernetesCommandLineToolsExecutor.loginToOcp('admin'); + expect(kubernetesCommandLineToolsExecutor.waitDevWorkspace().stdout).contains('condition met'); + }); - await runShellScript(createPredefinedProjectCommand); - await runShellScript(setEditRightsForUser); - }); + // verify that the newly created workspace, identified by a unique name, exists within the predefined namespace. Given that multiple users may use the same cluster and create multiple DevSpaces within the same OpenShift project, it's essential to confirm that our test project, distinguished by a unique name, has been successfully created. + test('Validate the creation of the correct DevWorkspace with a unique name', function (): void { + const ocDevWorkspaceOutput: string = kubernetesCommandLineToolsExecutor.getDevWorkspaceYamlConfiguration(); + expect(ocDevWorkspaceOutput).includes(workspaceName); + }); - 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 - workspaceHandlingTests.createAndOpenWorkspace('Empty Workspace'); - workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); - - // verify that just created workspace with unique name is present in the predefined namespace - test('Validate the created workspace is present in predefined namespace', async function (): Promise { - workspaceName = WorkspaceHandlingTests.getWorkspaceName(); - registerRunningWorkspace(workspaceName); - const ocDevWorkspaceOutput: string = await runShellScript(getDevWorkspaceFromPredefinedNameSpace); - await assert.isTrue(ocDevWorkspaceOutput.includes(workspaceName)); - }); - - loginTests.logoutFromChe(); + suiteTeardown(function (): void { + const workspaceName: string = WorkspaceHandlingTests.getWorkspaceName(); + try { + // the test can failed under the regular user. Need login as admin for removing test namespace and DevSpaces. + kubernetesCommandLineToolsExecutor.loginToOcp('admin'); + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + kubernetesCommandLineToolsExecutor.deleteProject(predefinedNamespaceName); + } catch (e) { + Logger.error(`Cannot remove the predefined project: ${workspaceName}, please fix it manually: ${e}`); + } + }); }); - - diff --git a/tests/e2e/specs/miscellaneous/RevokeOauth.spec.ts b/tests/e2e/specs/miscellaneous/RevokeOauth.spec.ts new file mode 100644 index 00000000000..364e49f69ce --- /dev/null +++ b/tests/e2e/specs/miscellaneous/RevokeOauth.spec.ts @@ -0,0 +1,32 @@ +/** ******************************************************************* + * copyright (c) 2020-2024 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 { CLASSES } from '../../configs/inversify.types'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { UserPreferences } from '../../pageobjects/dashboard/UserPreferences'; +import { FACTORY_TEST_CONSTANTS } from '../../constants/FACTORY_TEST_CONSTANTS'; + +suite('"Revoke OAuth" test', function (): void { + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const userPreferences: UserPreferences = e2eContainer.get(CLASSES.UserPreferences); + const gitService: string = FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_PROVIDER || 'github'; + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + + test('Revoke OAuth test', async function (): Promise { + await userPreferences.openUserPreferencesPage(); + await userPreferences.openGitServicesTab(); + + const selectedService: string = userPreferences.getServiceConfig(gitService); + await userPreferences.revokeGitService(selectedService); + }); +}); diff --git a/tests/e2e/specs/miscellaneous/UserPreferencesTest.spec.ts b/tests/e2e/specs/miscellaneous/UserPreferencesTest.spec.ts new file mode 100644 index 00000000000..cd22c46eeb5 --- /dev/null +++ b/tests/e2e/specs/miscellaneous/UserPreferencesTest.spec.ts @@ -0,0 +1,28 @@ +/** ******************************************************************* + * 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 { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { UserPreferences } from '../../pageobjects/dashboard/UserPreferences'; + +suite(`"Check User Preferences page" test ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const userPreferences: UserPreferences = e2eContainer.get(CLASSES.UserPreferences); + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + + test('Check user preferences page', async function (): Promise { + await userPreferences.openUserPreferencesPage(); + await userPreferences.checkTabsAvailability(); + }); +}); diff --git a/tests/e2e/specs/miscellaneous/WorkspaceIdleTimeout.spec.ts b/tests/e2e/specs/miscellaneous/WorkspaceIdleTimeout.spec.ts new file mode 100644 index 00000000000..9bc98d34576 --- /dev/null +++ b/tests/e2e/specs/miscellaneous/WorkspaceIdleTimeout.spec.ts @@ -0,0 +1,110 @@ +/** ******************************************************************* + * 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 { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +import { Workspaces } from '../../pageobjects/dashboard/Workspaces'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { CheCodeLocatorLoader } from '../../pageobjects/ide/CheCodeLocatorLoader'; +import { By, Locators, ModalDialog } from 'monaco-page-objects'; +import { expect } from 'chai'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ShellExecutor } from '../../utils/ShellExecutor'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; + +suite('"Check workspace idle timeout" test', function (): void { + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + const workspaces: Workspaces = e2eContainer.get(CLASSES.Workspaces); + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const cheCodeLocatorLoader: CheCodeLocatorLoader = e2eContainer.get(CLASSES.CheCodeLocatorLoader); + const webCheCodeLocators: Locators = cheCodeLocatorLoader.webCheCodeLocators; + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + + const stackName: string = 'Empty Workspace'; + const cheClusterName: string = 'devspaces'; + let stopWorkspaceTimeout: number = 0; + + async function checkDialogButton(buttonName: string): Promise { + await driverHelper.waitVisibility(By.xpath(`//div[@class='dialog-buttons']//a[text()='${buttonName}']`)); + } + + suiteSetup(function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp(); + shellExecutor.executeCommand('oc project openshift-devspaces'); + + // get current value of spec.devEnvironments.secondsOfInactivityBeforeIdling + stopWorkspaceTimeout = Number( + shellExecutor.executeCommand( + `oc get checluster/${cheClusterName} -o "jsonpath={.spec.devEnvironments.secondsOfInactivityBeforeIdling}"` + ) + ); + + // set spec.devEnvironments.secondsOfInactivityBeforeIdling to 60 + shellExecutor.executeCommand( + `oc patch checluster ${cheClusterName} --type=merge -p '{"spec":{"devEnvironments":{"secondsOfInactivityBeforeIdling": 60}}}'` + ); + }); + + suiteTeardown(function (): void { + // restore spec.devEnvironments.secondsOfInactivityBeforeIdling to original value + shellExecutor.executeCommand( + `oc patch checluster ${cheClusterName} --type=merge -p '{"spec":{"devEnvironments":{"secondsOfInactivityBeforeIdling": ${stopWorkspaceTimeout}}}}'` + ); + }); + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + + test(`Create and open new workspace, stack:${stackName}`, async function (): Promise { + await workspaceHandlingTests.createAndOpenWorkspace(stackName); + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + }); + + test('Wait workspace readiness', async function (): Promise { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + await projectAndFileTests.performTrustAuthorDialog(); + }); + + test('Wait idle timeout dialog and check Dialog buttons', async function (): Promise { + await driverHelper.waitVisibility(webCheCodeLocators.Dialog.details, TIMEOUT_CONSTANTS.TS_SELENIUM_START_WORKSPACE_TIMEOUT); + const dialog: ModalDialog = new ModalDialog(); + expect(await dialog.getDetails()).includes('Your workspace has stopped due to inactivity.'); + await checkDialogButton('Cancel'); + await checkDialogButton('Return to dashboard'); + await checkDialogButton('Restart your workspace'); + }); + + test('Check that the workspace has Stopped state', async function (): Promise { + await dashboard.openDashboard(); + await workspaces.waitWorkspaceWithStoppedStatus(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + await testWorkspaceUtil.deleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); +}); diff --git a/tests/e2e/specs/miscellaneous/WorkspaceWithParent.spec.ts b/tests/e2e/specs/miscellaneous/WorkspaceWithParent.spec.ts new file mode 100644 index 00000000000..c7fd451905e --- /dev/null +++ b/tests/e2e/specs/miscellaneous/WorkspaceWithParent.spec.ts @@ -0,0 +1,125 @@ +/** ******************************************************************* + * 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 { ShellExecutor } from '../../utils/ShellExecutor'; +import { InputBox, QuickOpenBox, QuickPickItem, ViewItem, ViewSection, Workbench } from 'monaco-page-objects'; +import { CLASSES, TYPES } from '../../configs/inversify.types'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { Dashboard } from '../../pageobjects/dashboard/Dashboard'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { expect } from 'chai'; +import { API_TEST_CONSTANTS } from '../../constants/API_TEST_CONSTANTS'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ITestWorkspaceUtil } from '../../utils/workspace/ITestWorkspaceUtil'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; +import { FACTORY_TEST_CONSTANTS } from '../../constants/FACTORY_TEST_CONSTANTS'; + +suite(`Workspace using a parent test suite ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil); + const dashboard: Dashboard = e2eContainer.get(CLASSES.Dashboard); + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); + const testWorkspaceUtil: ITestWorkspaceUtil = e2eContainer.get(TYPES.WorkspaceUtil); + const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + + let podName: string = ''; + + suiteSetup(function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp(); + }); + + suiteSetup('Login', async function (): Promise { + await loginTests.loginIntoChe(); + }); + + test('Create a workspace from child devfile', async function (): Promise { + const factoryUrl: string = + FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL.length === 0 + ? BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL + '/dashboard/#/' + 'https://github.com/testsfactory/parentDevfile' + : BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL + '/dashboard/#/' + FACTORY_TEST_CONSTANTS.TS_SELENIUM_FACTORY_GIT_REPO_URL; + await dashboard.waitPage(); + await browserTabsUtil.navigateTo(factoryUrl); + await workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + // add 10 sec timeout for waiting for finishing animation of all IDE parts (Welcome parts. bottom widgets. etc.) + // using 10 sec easier than performing of finishing animation a all elements + await driverHelper.wait(TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL); + await projectAndFileTests.performTrustAuthorDialog(); + }); + + test('Check cloning of the test project', async function (): Promise { + const expectedProjectItems: string[] = ['.devfile.yaml', 'parent.yaml', 'README.md', 'parentdevfile']; + const visibleContent: ViewSection = await projectAndFileTests.getProjectViewSession(); + for (const expectedProjectItem of expectedProjectItems) { + const visibleItem: ViewItem | undefined = await projectAndFileTests.getProjectTreeItem(visibleContent, expectedProjectItem); + expect(visibleItem).not.undefined; + } + }); + + test('Check devfile VS Code tasks ', async function (): Promise { + const input: QuickOpenBox | InputBox = await new Workbench().openCommandPrompt(); + await input.setText('>Tasks: Run Task'); + const runTaskItem: QuickPickItem | undefined = await input.findQuickPick('Tasks: Run Task'); + await runTaskItem?.click(); + // pause for avoiding StaleElement exception. It is easier solution than try/catch or writing separate function for this + await driverHelper.wait(TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING); + const devFileTask: QuickPickItem | undefined = await input.findQuickPick('devfile'); + await devFileTask?.click(); + // pause for avoiding StaleElement exception. It is easier solution than try/catch or writing separate function for this + await driverHelper.wait(TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING); + const firstExpectedQuickPick: QuickPickItem | undefined = await input.findQuickPick('1. This command from the devfile'); + const secondExpectedQuickPick: QuickPickItem | undefined = await input.findQuickPick('2. This command from the parent'); + expect(firstExpectedQuickPick).not.undefined; + expect(secondExpectedQuickPick).not.undefined; + }); + + test('Check expected containers in the parent POD', function (): void { + const getPodNameCommand: string = `${API_TEST_CONSTANTS.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL} get pods -n ${kubernetesCommandLineToolsExecutor.namespace} --selector=controller.devfile.io/devworkspace_name=sample-using-parent --output jsonpath=\'{.items[0].metadata.name}\'`; + + podName = shellExecutor.executeArbitraryShellScript(getPodNameCommand); + const containerNames: string = shellExecutor.executeArbitraryShellScript( + `${API_TEST_CONSTANTS.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL} get pod ${podName} -n ${kubernetesCommandLineToolsExecutor.namespace} --output jsonpath=\'{.spec.containers[*].name}\'` + ); + expect(containerNames).contains('tools').and.contains('che-gateway'); + + const initContainerName: string = shellExecutor.executeArbitraryShellScript( + `${API_TEST_CONSTANTS.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL} get pod ${podName} -n ${kubernetesCommandLineToolsExecutor.namespace} --output jsonpath=\'{.spec.initContainers[].name}\'` + ); + expect(initContainerName).contains('che-code-injector'); + }); + + test('Check expected environment variables', function (): void { + const envList: string = shellExecutor.executeArbitraryShellScript( + `${API_TEST_CONSTANTS.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL} -n admin-devspaces exec -i ${podName} -c tools -- sh -c env` + ); + expect(envList).contains('DEVFILE_ENV_VAR=true').and.contains('PARENT_ENV_VAR=true'); + }); + + suiteTeardown('Stop and delete the workspace by API', async function (): Promise { + await dashboard.openDashboard(); + await browserTabsUtil.closeAllTabsExceptCurrent(); + await testWorkspaceUtil.stopAndDeleteWorkspaceByName(WorkspaceHandlingTests.getWorkspaceName()); + }); + + suiteTeardown('Unregister running workspace', function (): void { + registerRunningWorkspace(''); + }); +}); diff --git a/tests/e2e/specs/web-terminal/WebTerminalTest.spec.ts b/tests/e2e/specs/web-terminal/WebTerminalTest.spec.ts new file mode 100644 index 00000000000..deaa2d0af18 --- /dev/null +++ b/tests/e2e/specs/web-terminal/WebTerminalTest.spec.ts @@ -0,0 +1,61 @@ +/** ******************************************************************* + * 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 { CLASSES } from '../../configs/inversify.types'; +import { e2eContainer } from '../../configs/inversify.config'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { OcpMainPage } from '../../pageobjects/openshift/OcpMainPage'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ShellExecutor } from '../../utils/ShellExecutor'; +import { expect } from 'chai'; +import { WebTerminalPage } from '../../pageobjects/webterminal/WebTerminalPage'; + +suite(`Login to Openshift console and start WebTerminal ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const webTerminal: WebTerminalPage = e2eContainer.get(CLASSES.WebTerminalPage); + const ocpMainPage: OcpMainPage = e2eContainer.get(CLASSES.OcpMainPage); + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); + + suiteSetup(function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp('admin'); + shellExecutor.executeCommand('oc project openshift-operators'); + }); + + loginTests.loginIntoOcpConsole(); + + test('Open Web Terminal', async function (): Promise { + await ocpMainPage.waitOpenMainPage(); + await webTerminal.openWebTerminal(); + }); + + test('Check username is correct', function (): void { + const userUid: string = shellExecutor.executeCommand('oc get user $(oc whoami) -o jsonpath={.metadata.uid}').replace(/\n/g, ''); + + // label selector for Web Terminal workspaces owned by the currently-logged in user + const labelSelector: string = 'console.openshift.io/terminal=true,controller.devfile.io/creator=' + userUid; + // namespace of this users web terminal + const namespace: string = shellExecutor.executeCommand( + `oc get dw -A -l ${labelSelector} -o jsonpath='{.items[0].metadata.namespace}'` + ); + // devWorkspace ID for this users web terminal + const termDwId: string = shellExecutor.executeCommand( + `oc get dw -A -l ${labelSelector} -o jsonpath='{.items[0].status.devworkspaceId}'` + ); + // use oc exec to run oc whoami inside this user's terminal + const user: string = shellExecutor + .executeCommand(`oc exec -n ${namespace} deploy/${termDwId} -c web-terminal-tooling -- oc whoami`) + .replace(/\n/g, ''); + // above should output current user's username: + expect(user).to.equal(shellExecutor.executeCommand('oc whoami').replace(/\n/g, '')); + }); +}); diff --git a/tests/e2e/specs/web-terminal/WebTerminalUnderAdmin.spec.ts b/tests/e2e/specs/web-terminal/WebTerminalUnderAdmin.spec.ts new file mode 100644 index 00000000000..6c295d89de6 --- /dev/null +++ b/tests/e2e/specs/web-terminal/WebTerminalUnderAdmin.spec.ts @@ -0,0 +1,97 @@ +/** ******************************************************************* + * copyright (c) 2024 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { CLASSES } from '../../configs/inversify.types'; +import { e2eContainer } from '../../configs/inversify.config'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { OcpMainPage } from '../../pageobjects/openshift/OcpMainPage'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ShellExecutor } from '../../utils/ShellExecutor'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { WebTerminalPage } from '../../pageobjects/webterminal/WebTerminalPage'; +import { expect } from 'chai'; +import YAML from 'yaml'; + +suite(`Login to Openshift console and start WebTerminal ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const ocpMainPage: OcpMainPage = e2eContainer.get(CLASSES.OcpMainPage); + const webTerminal: WebTerminalPage = e2eContainer.get(CLASSES.WebTerminalPage); + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + const defaultWTOProjectNameForAdmin: string = 'openshift-terminal'; + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + const webTerminalToolContainerName: string = 'web-terminal-tooling'; + const fileForVerificationTerminalCommands: string = 'result.txt'; + + suiteSetup(function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp('admin'); + }); + + suiteTeardown(function (): void { + shellExecutor.executeArbitraryShellScript(`oc delete dw --all -n ${defaultWTOProjectNameForAdmin}`); + }); + loginTests.loginIntoOcpConsole(); + test('Open Web Terminal after first installation', async function (): Promise { + await ocpMainPage.waitOpenMainPage(); + await driverHelper.refreshPage(); + await webTerminal.clickOnWebTerminalIcon(); + }); + test('Verify first started WTO widget and disabled state Project field under admin user', async function (): Promise { + await webTerminal.waitTerminalWidget(); + expect(await webTerminal.waitDisabledProjectFieldAndGetProjectName()).equal(defaultWTOProjectNameForAdmin); + }); + test('Check starting Web Terminal under admin', async function (): Promise { + kubernetesCommandLineToolsExecutor.namespace = await webTerminal.getAdminProjectName(); + await webTerminal.clickOnStartWebTerminalButton(); + await webTerminal.waitTerminalIsStarted(); + await webTerminal.typeAndEnterIntoWebTerminal(`oc whoami > ${fileForVerificationTerminalCommands}`); + const devWorkspaceYaml: string = shellExecutor.executeArbitraryShellScript( + `oc get dw -n ${kubernetesCommandLineToolsExecutor.namespace} -o yaml` + ); + kubernetesCommandLineToolsExecutor.workspaceName = YAML.parse(devWorkspaceYaml).items[0].metadata.name; + kubernetesCommandLineToolsExecutor.getPodAndContainerNames(); + const commandResult: string = kubernetesCommandLineToolsExecutor.execInContainerCommand( + `cat /home/user/${fileForVerificationTerminalCommands}`, + webTerminalToolContainerName + ); + expect(commandResult).contains('admin'); + }); + test('Verify help command under admin user', async function (): Promise { + const helpCommandExpectedResult: string = + 'oc.*\\d+\\.\\d+\\.\\d+.*OpenShift CLI\n' + + 'kubectl.*\\d+\\.\\d+\\.\\d+.*Kubernetes CLI\n' + + 'kustomize.*\\d+\\.\\d+\\.\\d+.*Kustomize CLI\n' + + 'helm.*\\d+\\.\\d+\\.\\d+.*Helm CLI\n' + + 'kn.*\\d+\\.\\d+\\.\\d+.*KNative CLI\n' + + 'tkn.*\\d+\\.\\d+\\.\\d+.*Tekton CLI\n' + + 'subctl.*\\d+\\.\\d+\\.\\d+.*Submariner CLI\n' + + 'odo.*\\d+\\.\\d+\\.\\d+.*Red Hat OpenShift Developer CLI\n' + + 'virtctl.*\\d+\\.\\d+\\.\\d+.*KubeVirt CLI\n' + + 'rhoas.*\\d+\\.\\d+\\.\\d+.*Red Hat OpenShift Application Services CLI\n' + + 'jq.*\\d+\\.\\d+.*jq'; + + await webTerminal.typeAndEnterIntoWebTerminal(`help > ${fileForVerificationTerminalCommands}`); + + // need 5 sec. delay for finishing writing results of help command into txt file. The 5 sec delay is enough for the most cases + await driverHelper.wait(5000); + const commandResult: string = kubernetesCommandLineToolsExecutor.execInContainerCommand( + `cat /home/user/${fileForVerificationTerminalCommands}`, + webTerminalToolContainerName + ); + expect(commandResult).to.match(new RegExp(helpCommandExpectedResult)); + }); + + test('Verify help command under admin user', async function (): Promise { + await webTerminal.typeAndEnterIntoWebTerminal('wtoctl set timeout 30s'); + await webTerminal.waitTerminalInactivity(); + }); +}); diff --git a/tests/e2e/specs/web-terminal/WebTerminalUnderRegularUser.spec.ts b/tests/e2e/specs/web-terminal/WebTerminalUnderRegularUser.spec.ts new file mode 100644 index 00000000000..a6b8dcea30f --- /dev/null +++ b/tests/e2e/specs/web-terminal/WebTerminalUnderRegularUser.spec.ts @@ -0,0 +1,91 @@ +/** ******************************************************************* + * copyright (c) 2024 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { CLASSES } from '../../configs/inversify.types'; +import { e2eContainer } from '../../configs/inversify.config'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { OcpMainPage } from '../../pageobjects/openshift/OcpMainPage'; +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { ShellExecutor } from '../../utils/ShellExecutor'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { TimeUnits, WebTerminalPage } from '../../pageobjects/webterminal/WebTerminalPage'; +import { expect } from 'chai'; +import YAML from 'yaml'; +import { afterEach } from 'mocha'; +import { By } from 'selenium-webdriver'; + +suite(`Login to Openshift console and check WebTerminal ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + const webTerminalToolContainerName: string = 'web-terminal-tooling'; + const testProjectName: string = 'wto-under-regular-user-test'; + const fileForVerificationTerminalCommands: string = 'result.txt'; + const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); + const ocpMainPage: OcpMainPage = e2eContainer.get(CLASSES.OcpMainPage); + const webTerminal: WebTerminalPage = e2eContainer.get(CLASSES.WebTerminalPage); + const shellExecutor: ShellExecutor = e2eContainer.get(CLASSES.ShellExecutor); + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + + const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); + + suiteSetup(function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp(); + }); + + suiteTeardown(function (): void { + kubernetesCommandLineToolsExecutor.deleteProject(testProjectName); + }); + + afterEach(function (): void { + try { + shellExecutor.executeArbitraryShellScript(`oc delete dw --all -n ${testProjectName}`); + } catch (e) { + console.log(`cannot delete the ${testProjectName} under regular user:`, e); + } + }); + + loginTests.loginIntoOcpConsole(); + + test('Open WebTerminal after first installation', async function (): Promise { + await ocpMainPage.waitOpenMainPage(); + await driverHelper.refreshPage(); + await webTerminal.clickOnWebTerminalIcon(); + }); + + test('Check WebTerminal with creating new Openshift Project', async function (): Promise { + kubernetesCommandLineToolsExecutor.namespace = testProjectName; + await webTerminal.typeProjectName(testProjectName); + await webTerminal.clickOnStartWebTerminalButton(); + await webTerminal.waitTerminalIsStarted(); + await webTerminal.typeAndEnterIntoWebTerminal(`oc whoami > ${fileForVerificationTerminalCommands}`); + const devWorkspaceYaml: string = shellExecutor.executeArbitraryShellScript( + `oc get dw -n ${kubernetesCommandLineToolsExecutor.namespace} -o yaml` + ); + kubernetesCommandLineToolsExecutor.workspaceName = YAML.parse(devWorkspaceYaml).items[0].metadata.name; + kubernetesCommandLineToolsExecutor.getPodAndContainerNames(); + const commandResult: string = kubernetesCommandLineToolsExecutor.execInContainerCommand( + `cat /home/user/${fileForVerificationTerminalCommands}`, + webTerminalToolContainerName + ); + const currentUserName: string = await driverHelper.waitAndGetText(By.css('span[data-test="username"]')); + expect(commandResult).contains(currentUserName); + }); + + test('Check running WebTerminal in the existed Project with custom timeout', async function (): Promise { + await webTerminal.findAndSelectProject(testProjectName); + await webTerminal.clickOnTimeoutButton(); + await webTerminal.clickOnTimeUnitDropDown(); + await webTerminal.selectTimeUnit(TimeUnits.Seconds); + await webTerminal.setTimeoutByEntering(20); + await webTerminal.clickOnStartWebTerminalButton(); + await webTerminal.waitTerminalIsStarted(); + await webTerminal.waitTerminalInactivity(); + }); +}); diff --git a/tests/e2e/suites/devfile-acceptance-test-suite/DynamicallyGeneratingAPITest.suite.ts b/tests/e2e/suites/devfile-acceptance-test-suite/DynamicallyGeneratingAPITest.suite.ts new file mode 100644 index 00000000000..c500cedc87c --- /dev/null +++ b/tests/e2e/suites/devfile-acceptance-test-suite/DynamicallyGeneratingAPITest.suite.ts @@ -0,0 +1,10 @@ +/** ******************************************************************* + * 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 '../../specs/api/DevfileAcceptanceTestAPI.spec'; diff --git a/tests/e2e/suites/disconnected-ocp/APITest.suite.ts b/tests/e2e/suites/disconnected-ocp/APITest.suite.ts new file mode 100644 index 00000000000..4ab3bbded65 --- /dev/null +++ b/tests/e2e/suites/disconnected-ocp/APITest.suite.ts @@ -0,0 +1,11 @@ +/** ******************************************************************* + * 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 '../../specs/api/ContainerOverridesAPI.spec'; +import '../../specs/api/PodOverridesAPI.spec'; diff --git a/tests/e2e/suites/disconnected-ocp/DynamicallyGeneratingAPITest.suite.ts b/tests/e2e/suites/disconnected-ocp/DynamicallyGeneratingAPITest.suite.ts new file mode 100644 index 00000000000..99713b8dab3 --- /dev/null +++ b/tests/e2e/suites/disconnected-ocp/DynamicallyGeneratingAPITest.suite.ts @@ -0,0 +1,10 @@ +/** ******************************************************************* + * 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 '../../specs/api/InbuiltApplicationDevWorkspacesAPI.spec'; diff --git a/tests/e2e/suites/disconnected-ocp/UITest.suite.ts b/tests/e2e/suites/disconnected-ocp/UITest.suite.ts new file mode 100644 index 00000000000..879138158a0 --- /dev/null +++ b/tests/e2e/suites/disconnected-ocp/UITest.suite.ts @@ -0,0 +1,16 @@ +/** ******************************************************************* + * 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 '../../specs/dashboard-samples/Quarkus.spec'; +import '../../specs/dashboard-samples/RecommendedExtensions.spec'; +import '../../specs/dashboard-samples/Documentation.spec'; +import '../../specs/devconsole-intergration/DevConsoleIntegration.spec'; +import '../../specs/miscellaneous/CreateWorkspaceWithExistedName.spec'; +import '../../specs/miscellaneous/WorkspaceWithParent.spec'; +import '../../specs/miscellaneous/PredefinedNamespace.spec'; diff --git a/tests/e2e/suites/online-ocp/APITest.suite.ts b/tests/e2e/suites/online-ocp/APITest.suite.ts new file mode 100644 index 00000000000..94da2010975 --- /dev/null +++ b/tests/e2e/suites/online-ocp/APITest.suite.ts @@ -0,0 +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 '../../specs/api/ContainerOverridesAPI.spec'; +import '../../specs/api/EmptyWorkspaceAPI.spec'; +import '../../specs/api/PodOverridesAPI.spec'; diff --git a/tests/e2e/suites/online-ocp/DynamicallyGeneratingAPITest.suite.ts b/tests/e2e/suites/online-ocp/DynamicallyGeneratingAPITest.suite.ts new file mode 100644 index 00000000000..99713b8dab3 --- /dev/null +++ b/tests/e2e/suites/online-ocp/DynamicallyGeneratingAPITest.suite.ts @@ -0,0 +1,10 @@ +/** ******************************************************************* + * 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 '../../specs/api/InbuiltApplicationDevWorkspacesAPI.spec'; diff --git a/tests/e2e/suites/online-ocp/UITest.suite.ts b/tests/e2e/suites/online-ocp/UITest.suite.ts new file mode 100644 index 00000000000..0899211f776 --- /dev/null +++ b/tests/e2e/suites/online-ocp/UITest.suite.ts @@ -0,0 +1,19 @@ +/** ******************************************************************* + * 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 '../../specs/SmokeTest.spec'; +import '../../specs/dashboard-samples/EmptyWorkspace.spec'; +import '../../specs/dashboard-samples/Quarkus.spec'; +import '../../specs/dashboard-samples/RecommendedExtensions.spec'; +import '../../specs/dashboard-samples/Documentation.spec'; +import '../../specs/devconsole-intergration/DevConsoleIntegration.spec'; +import '../../specs/miscellaneous/CreateWorkspaceWithExistedName.spec'; +import '../../specs/miscellaneous/KubedockPodmanTest.spec'; +import '../../specs/miscellaneous/WorkspaceWithParent.spec'; +import '../../specs/miscellaneous/PredefinedNamespace.spec'; diff --git a/tests/e2e/tests-library/LoginTests.ts b/tests/e2e/tests-library/LoginTests.ts index 2b6577657b6..2525f3cece0 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,54 @@ 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'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; +import { Logger } from '../utils/Logger'; @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(); - }); - } + async loginIntoChe( + userName?: string, + password?: string, + timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ): Promise { + Logger.debug(); + try { + 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.dashboard.waitPage(timeout); + Logger.debug('user already logged in'); + } catch (e) { + Logger.debug('try to login into application'); + await this.productLoginPage.login(userName, password); + 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 { + suiteSetup('Login into ocp console', async (): Promise => { + const openshiftConsoleUrl: string = BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL.replace( + BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME(), + 'console-openshift-console' + ); + await this.browserTabsUtil.navigateTo(openshiftConsoleUrl); + await this.ocpLoginPage.login(); + await this.browserTabsUtil.maximize(); + }); + } - logoutFromChe(): void { - test('Logout', async () => { - await this.dashboard.logout(); - }); - } + async logoutFromChe(): Promise { + await this.dashboard.logout(); + } } diff --git a/tests/e2e/tests-library/LoginTests.ts.orig b/tests/e2e/tests-library/LoginTests.ts.orig new file mode 100644 index 00000000000..07afd192f95 --- /dev/null +++ b/tests/e2e/tests-library/LoginTests.ts.orig @@ -0,0 +1,93 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { CLASSES, TYPES } from '../configs/inversify.types'; +import { ICheLoginPage } from '../pageobjects/login/interfaces/ICheLoginPage'; +import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; +import { inject, injectable } from 'inversify'; +import { Dashboard } from '../pageobjects/dashboard/Dashboard'; +import { IOcpLoginPage } from '../pageobjects/login/interfaces/IOcpLoginPage'; +<<<<<<< HEAD +import { BaseTestConstants } from '../constants/BaseTestConstants'; +======= +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; +import { Logger } from '../utils/Logger'; +>>>>>>> main + +@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 + ) {} + +<<<<<<< HEAD + 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(); + }); + } + + 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(); + }); + } +======= + async loginIntoChe( + userName?: string, + password?: string, + timeout: number = TIMEOUT_CONSTANTS.TS_COMMON_DASHBOARD_WAIT_TIMEOUT + ): Promise { + Logger.debug(); + try { + 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.dashboard.waitPage(timeout); + Logger.debug('user already logged in'); + } catch (e) { + Logger.debug('try to login into application'); + await this.productLoginPage.login(userName, password); + await this.browserTabsUtil.maximize(); + await this.dashboard.waitStartingPageLoaderDisappearance(); + } + } + + loginIntoOcpConsole(): void { + suiteSetup('Login into ocp console', async (): Promise => { + const openshiftConsoleUrl: string = BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL.replace( + BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME(), + 'console-openshift-console' + ); + await this.browserTabsUtil.navigateTo(openshiftConsoleUrl); + await this.ocpLoginPage.login(); + await this.browserTabsUtil.maximize(); + }); + } +>>>>>>> main + + async logoutFromChe(): Promise { + await this.dashboard.logout(); + } +} diff --git a/tests/e2e/tests-library/ProjectAndFileTests.ts b/tests/e2e/tests-library/ProjectAndFileTests.ts index e310781b08e..c7a312a09af 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 @@ -10,28 +10,145 @@ import 'reflect-metadata'; import { inject, injectable } from 'inversify'; -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'; +import { CheCodeLocatorLoader } from '../pageobjects/ide/CheCodeLocatorLoader'; +import { By, SideBarView, ViewContent, ViewItem, ViewSection, Workbench } from 'monaco-page-objects'; @injectable() export class ProjectAndFileTests { + private static BRANCH_NAME_XPATH: By = By.xpath('//a[contains(@aria-label,"Checkout Branch/Tag...")]'); - constructor( - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) {} - - async waitWorkspaceReadinessForCheCodeEditor(): Promise { - Logger.debug(`${this.constructor.name}.${this.waitWorkspaceReadinessForCheCodeEditor.name} - 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(`${this.constructor.name}.${this.waitWorkspaceReadinessForCheCodeEditor.name} - editor was opened in ${end - start} seconds.`); - } catch (err) { - Logger.error(`ProjectAndFileTestsCheCode.waitWorkspaceReadinessForCheCodeEditor - waiting for workspace readiness failed: ${err}`); - throw err; - } - } + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper, + @inject(CLASSES.CheCodeLocatorLoader) + private readonly cheCodeLocatorLoader: CheCodeLocatorLoader + ) {} + + async waitWorkspaceReadinessForCheCodeEditor(): Promise { + Logger.debug('waiting for editor.'); + try { + const start: number = new Date().getTime(); + await this.driverHelper.waitVisibility( + this.cheCodeLocatorLoader.webCheCodeLocators.Workbench.constructor, + 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; + } + } + + async performTrustAuthorDialog(): Promise { + Logger.debug(); + // sometimes the trust dialog does not appear at first time, for avoiding this problem we send click event for activating + const workbench: Workbench = new Workbench(); + + try { + await workbench.click(); + await this.driverHelper.waitAndClick( + this.cheCodeLocatorLoader.webCheCodeLocators.WelcomeContent.button, + TIMEOUT_CONSTANTS.TS_DIALOG_WINDOW_DEFAULT_TIMEOUT + ); + } catch (e) { + Logger.info('Second welcome content dialog box was not shown'); + } + } + + /** + * manage to 'Trusted' Workspace Mode, when the trust author dialog does not appear + * the "Manage Workspace Trust" box is appeared in Source Control View + */ + async performManageWorkspaceTrustBox(): Promise { + Logger.debug(); + + try { + await this.driverHelper.waitAndClick( + (this.cheCodeLocatorLoader.webCheCodeLocators.ScmView as any).manageWorkspaceTrust, + TIMEOUT_CONSTANTS.TS_DIALOG_WINDOW_DEFAULT_TIMEOUT + ); + await this.driverHelper.waitAndClick( + (this.cheCodeLocatorLoader.webCheCodeLocators.Workbench as any).workspaceTrustButton, + TIMEOUT_CONSTANTS.TS_DIALOG_WINDOW_DEFAULT_TIMEOUT + ); + await this.driverHelper.waitAndClick( + (this.cheCodeLocatorLoader.webCheCodeLocators.ScmView as any).modifiedFile, + TIMEOUT_CONSTANTS.TS_DIALOG_WINDOW_DEFAULT_TIMEOUT + ); + } catch (err) { + Logger.error(`Manage Workspace Trust box was not shown: ${err}`); + throw err; + } + } + + /** + * find an ViewSection with project tree. + * @returns Promise resolving to ViewSection object + */ + + async getProjectViewSession(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility( + this.cheCodeLocatorLoader.webCheCodeLocators.DefaultTreeSection.itemRow, + TIMEOUT_CONSTANTS.TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT + ); + + const viewContent: ViewContent = new SideBarView().getContent(); + const [projectSection]: ViewSection[] = await viewContent.getSections(); + return projectSection; + } + + /** + * find an item in this view section by label. Does not perform recursive search through the whole tree. + * Does however scroll through all the expanded content. Will find items beyond the current scroll range. + * @param projectSection ViewSection with project tree files. + * @param label Label of the item to search for. + * @param itemLevel Shows how deep the algorithm should look into expanded folders to find item, + * default - 2 means first level is project directory and files inside it is the second level, unlimited 0 + * @returns Promise resolving to ViewItem object is such item exists, undefined otherwise + */ + async getProjectTreeItem(projectSection: ViewSection, label: string, itemLevel: number = 2): Promise { + Logger.debug(`${label}`); + + let projectTreeItem: ViewItem | undefined; + await this.driverHelper.waitVisibility( + this.cheCodeLocatorLoader.webCheCodeLocators.ScmView.itemLevel(itemLevel), + TIMEOUT_CONSTANTS.TS_EXPAND_PROJECT_TREE_ITEM_TIMEOUT + ); + + try { + projectTreeItem = await projectSection.findItem(label, itemLevel); + if (!projectTreeItem) { + try { + await projectSection.collapse(); + projectTreeItem = await projectSection.findItem(label, itemLevel); + } catch (e) { + Logger.warn(JSON.stringify(e)); + } + } + } catch (e) { + Logger.warn(JSON.stringify(e)); + } + + return projectTreeItem; + } + + /** + * @returns {string} Branch name of cloned repository + */ + + async getBranchName(): Promise { + Logger.debug(); + + await this.driverHelper.waitVisibility(ProjectAndFileTests.BRANCH_NAME_XPATH, TIMEOUT_CONSTANTS.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + const output: string = await this.driverHelper.waitAndGetText(ProjectAndFileTests.BRANCH_NAME_XPATH); + + return output.trimStart(); + } } diff --git a/tests/e2e/tests-library/WorkspaceHandlingTests.ts b/tests/e2e/tests-library/WorkspaceHandlingTests.ts index 712874cf6e6..2c2a2df8f1b 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 @@ -13,129 +13,124 @@ import { inject, injectable } from 'inversify'; import { CLASSES } from '../configs/inversify.types'; import { Dashboard } from '../pageobjects/dashboard/Dashboard'; import { CreateWorkspace } from '../pageobjects/dashboard/CreateWorkspace'; -import { Workspaces } from '../pageobjects/dashboard/Workspaces'; 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: 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.Workspaces) private readonly workspaces: Workspaces, - @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil, - @inject(CLASSES.ApiUrlResolver) private readonly apiUrlResolver: ApiUrlResolver, - @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) {} + static clearWorkspaceName(): void { + WorkspaceHandlingTests.workspaceName = 'undefined'; + } - setWindowHandle(guid: string): void { - WorkspaceHandlingTests.parentGUID = guid; - } + 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); + } - getWindowHandle(): string { - return WorkspaceHandlingTests.parentGUID; - } + async createAndOpenWorkspaceFromGitRepository(factoryUrl: string, branchName?: 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, branchName); + await this.browserTabsUtil.waitAndSwitchToAnotherWindow(WorkspaceHandlingTests.parentGUID, TIMEOUT_CONSTANTS.TS_IDE_LOAD_TIMEOUT); + } - createAndOpenWorkspace(stack: string): void { - test(`Create and open new workspace, stack:${stack}`, async () => { - 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 createAndOpenWorkspaceWithExistedWorkspaceName(stack: string): Promise { + Logger.debug('create and open workspace with existed workspace name.'); + await this.createAndOpenWorkspace(stack); + await this.dashboard.waitExistingWorkspaceFoundAlert(); + await this.dashboard.clickOnCreateNewWorkspaceButton(); + } - createAndOpenWorkspaceFromGitRepository(factoryUrl: string): void { - test(`Create and open new workspace from factory:${factoryUrl}`, async () => { - 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 { + await this.createWorkspace.performTrustAuthorPopup(); - openExistingWorkspace(workspaceName: string): void { - test('Open and start existing workspace', async () => { - 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.clickWorkspacesButton(); - await this.workspaces.waitPage(); - await this.workspaces.clickOpenButton(workspaceName); - }); - } + const timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_START_WORKSPACE_TIMEOUT; + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); - obtainWorkspaceNameFromStartingPage(): void { - test('Obtain workspace name from workspace loader page', async() => { - 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) + .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(`WorkspaceHandlingTests.obtainWorkspaceNameFromStartingPage obtained starting workspace getText():${startingWorkspaceLineContent}`); - // cutting away leading text - WorkspaceHandlingTests.workspaceName = startingWorkspaceLineContent.substring('Starting workspace '.length).trim(); - Logger.trace(`WorkspaceHandlingTests.obtainWorkspaceNameFromStartingPage trimmed workspace name from getText():${WorkspaceHandlingTests.workspaceName}`); - break; - } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - Logger.trace(`WorkspaceHandlingTests.obtainWorkspaceNameFromStartingPage 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(`WorkspaceHandlingTests.obtainWorkspaceNameFromStartingPage Failed to obtain name from workspace start page, element not visible yet. Retrying.`); - await this.driverHelper.wait(polling); - continue; - } - Logger.error(`WorkspaceHandlingTests.obtainWorkspaceNameFromStartingPage 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(`WorkspaceHandlingTests.obtainWorkspaceNameFromStartingPage 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/tests-library/WorkspaceHandlingTests.ts.orig b/tests/e2e/tests-library/WorkspaceHandlingTests.ts.orig new file mode 100644 index 00000000000..916d1638e9e --- /dev/null +++ b/tests/e2e/tests-library/WorkspaceHandlingTests.ts.orig @@ -0,0 +1,144 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import 'reflect-metadata'; +import { inject, injectable } from 'inversify'; +import { CLASSES } from '../configs/inversify.types'; +import { Dashboard } from '../pageobjects/dashboard/Dashboard'; +import { CreateWorkspace } from '../pageobjects/dashboard/CreateWorkspace'; +import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; +import { Logger } from '../utils/Logger'; +import { ApiUrlResolver } from '../utils/workspace/ApiUrlResolver'; +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: By = By.xpath('//h1[contains(.,"Starting workspace ")]'); + private static workspaceName: string = 'undefined'; + private static parentGUID: string; + + 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 + ) {} + + static getWorkspaceName(): string { + return WorkspaceHandlingTests.workspaceName; + } + + static clearWorkspaceName(): void { + WorkspaceHandlingTests.workspaceName = 'undefined'; + } + + 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 createAndOpenWorkspaceFromGitRepository(factoryUrl: string, branchName?: 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, branchName); + await this.browserTabsUtil.waitAndSwitchToAnotherWindow(WorkspaceHandlingTests.parentGUID, TIMEOUT_CONSTANTS.TS_IDE_LOAD_TIMEOUT); + } + + async createAndOpenWorkspaceWithExistedWorkspaceName(stack: string): Promise { + Logger.debug('create and open workspace with existed workspace name.'); + await this.createAndOpenWorkspace(stack); + await this.dashboard.waitExistingWorkspaceFoundAlert(); + await this.dashboard.clickOnCreateNewWorkspaceButton(); + } + + async obtainWorkspaceNameFromStartingPage(): Promise { + await this.createWorkspace.performTrustAuthorPopup(); + + const timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_START_WORKSPACE_TIMEOUT; + const polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + +<<<<<<< HEAD + obtainWorkspaceNameFromStartingPage(): void { + test('Obtain workspace name from workspace loader page', async() => { + 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) + .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}` + ); + } +>>>>>>> main + + 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 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..7357caec767 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": "es2021", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "outDir": "dist", + "lib": ["es2021", "dom"], + "types": ["reflect-metadata", "@types/mocha", "@types/node"], + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "noImplicitReturns": false, + "sourceMap": true + }, + "include": [".eslintrc.js", "**/*.ts", "**/**/*.ts", "**/reporters.config.js"] } 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 bc3f17c748d..2168cbb2c08 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 @@ -8,106 +8,121 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { injectable, inject } from 'inversify'; +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 { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; @injectable() export class BrowserTabsUtil { - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - async switchToWindow(windowHandle: string): Promise { - Logger.debug('BrowserTabsUtil.switchToWindow'); - await this.driverHelper.getDriver().switchTo().window(windowHandle); - } + 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.navigateToUrl(url); + } + + async waitAndSwitchToAnotherWindow( + currentWindowHandle: string, + timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL + ): 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 { + Logger.trace(); + + let currentUrl: string = ''; + try { + currentUrl = await this.driverHelper.getDriver().getCurrentUrl(); + } catch (e) { + Logger.trace('cannot get current url'); + } + + return currentUrl; + } + + 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); - async getAllWindowHandles(): Promise { - Logger.debug('BrowserTabsUtil.getAllWindowHandles'); - - return (await this.driverHelper.getDriver()).getAllWindowHandles(); - } - - async getCurrentWindowHandle(): Promise { - Logger.debug('BrowserTabsUtil.getCurrentWindowHandle'); - - return await this.driverHelper.getDriver().getWindowHandle(); - } - - async navigateTo(url: string): Promise { - Logger.debug(`BrowserTabsUtil.navigateTo ${url}`); - - await this.driverHelper.getDriver().navigate().to(url); - } - - async navigateAndWaitToUrl(url: string, timeout: number = TimeoutConstants.TS_SELENIUM_WAIT_FOR_URL): Promise { - Logger.trace(`BrowserTabsUtil.navigateAndWaitToUrl ${url}`); - - await this.navigateTo(url); - await this.waitURL(url, timeout); - } - - async waitAndSwitchToAnotherWindow(currentWindowHandle: string, timeout: number): Promise { - Logger.debug('BrowserTabsUtil.waitAndSwitchToAnotherWindow'); - - 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('BrowserTabsUtil.refreshPage'); - - 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(`BrowserTabsUtil.waitURL ${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(`BrowserTabsUtil.maximize`); - 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(`${this.constructor.name}.${this.closeAllTabsExceptCurrent.name}`); - 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); - } + for (const tabHandle of allTabsHandles) { + await this.switchToWindow(tabHandle); + await this.driverHelper.getDriver().close(); + } + await this.switchToWindow(currentTabHandle); + } } diff --git a/tests/e2e/utils/BrowserTabsUtil.ts.orig b/tests/e2e/utils/BrowserTabsUtil.ts.orig new file mode 100644 index 00000000000..23bfefc1672 --- /dev/null +++ b/tests/e2e/utils/BrowserTabsUtil.ts.orig @@ -0,0 +1,143 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { inject, injectable } from 'inversify'; +import { CLASSES } from '../configs/inversify.types'; +import { DriverHelper } from './DriverHelper'; +import { Logger } from './Logger'; +<<<<<<< HEAD +import { TimeoutConstants } from '../constants/TimeoutConstants'; +import { ChromeDriverConstants } from '../constants/ChromeDriverConstants'; +======= +import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; +>>>>>>> main + +@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.navigateToUrl(url); + } + + async waitAndSwitchToAnotherWindow( + currentWindowHandle: string, + timeout: number = TIMEOUT_CONSTANTS.TS_SELENIUM_WAIT_FOR_URL + ): 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 { + Logger.trace(); + + let currentUrl: string = ''; + try { + currentUrl = await this.driverHelper.getDriver().getCurrentUrl(); + } catch (e) { + Logger.trace('cannot get current url'); + } + + return currentUrl; + } + + 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; + +<<<<<<< HEAD + async maximize(): Promise { + Logger.trace(`BrowserTabsUtil.maximize`); + 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(); + } + } +======= + if (urlEquals) { + return true; + } + }, timeout); + } catch (e) { + throw e; + } + } +>>>>>>> main + + 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 fc97c2bedcb..ccbc0b11eef 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 @@ -7,179 +7,220 @@ * * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import * as chromeHar from 'chrome-har'; import * as mocha from 'mocha'; import { CLASSES } from '../configs/inversify.types'; import * as fs from 'fs'; +import { WriteStream } from 'fs'; 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 { WriteStream } from 'fs'; 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'; +import { injectable } from 'inversify'; +import getDecorators from 'inversify-inject-decorators'; +import { e2eContainer } from '../configs/inversify.config'; -const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); -const screenCatcher: ScreenCatcher = e2eContainer.get(CLASSES.ScreenCatcher); -let methodIndex: number = 0; -let deleteScreencast: boolean = true; +const { lazyInject } = getDecorators(e2eContainer); +@injectable() class CheReporter extends mocha.reporters.Spec { - - constructor(runner: mocha.Runner, options: mocha.MochaOptions) { - super(runner, options); - - runner.on('start', async (): Promise => { - let launchInformation: string = - `################## Launch Information ################## - - 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: ${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: ${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} - - ${process.env.MOCHA_DIRECTORY ? 'MOCHA_DIRECTORY: ' + process.env.MOCHA_DIRECTORY : 'MOCHA_DRIRECTORY is not set'} + private static methodIndex: number = 0; + private static deleteScreencast: boolean = true; + @lazyInject(CLASSES.DriverHelper) + private readonly driverHelper!: DriverHelper; + @lazyInject(CLASSES.ScreenCatcher) + private readonly screenCatcher!: ScreenCatcher; + + constructor(runner: mocha.Runner, options: mocha.MochaOptions) { + super(runner, options); + + runner.on('start', (): void => { + 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_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} + + ${process.env.TS_SELENIUM_PROXY_SERVER ? 'TS_SELENIUM_PROXY_SERVER: ' + process.env.TS_SELENIUM_PROXY_SERVER : ''} + + 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_SAMPLE_LIST: ${PLUGIN_TEST_CONSTANTS.TS_SAMPLE_LIST} + + ${process.env.MOCHA_DIRECTORY ? 'MOCHA_DIRECTORY: ' + process.env.MOCHA_DIRECTORY : 'MOCHA_DIRECTORY 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 (test: mocha.Test): Promise => { + if (!REPORTER_CONSTANTS.TS_SELENIUM_EXECUTION_SCREENCAST) { + return; + } + + CheReporter.methodIndex = CheReporter.methodIndex + 1; + const currentMethodIndex: number = CheReporter.methodIndex; + let iterationIndex: number = 1; + + while (!(test.state === 'passed' || test.state === 'failed')) { + await this.screenCatcher.catchMethodScreen(test.title, currentMethodIndex, iterationIndex); + iterationIndex = iterationIndex + 1; + + await this.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', (): void => { + // delete screencast folder if conditions matched + if (CheReporter.deleteScreencast && REPORTER_CONSTANTS.DELETE_SCREENCAST_IF_TEST_PASS) { + rm.sync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + } + }); + + runner.on('fail', async (test: mocha.Test): Promise => { + Logger.error(`CheReporter runner.on.fail: ${test.fullTitle()} failed after ${test.duration}ms`); + // raise flag for keeping the screencast + CheReporter.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`; + const harFileName: string = `${testReportDirPath}/har-${testTitle}.har`; + + // 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 this.driverHelper.getDriver().takeScreenshot(); + const screenshotStream: WriteStream = fs.createWriteStream(screenshotFileName); + screenshotStream.write(Buffer.from(screenshot, 'base64'), (): void => screenshotStream.end()); + + // take page source and write to file + const pageSource: string = await this.driverHelper.getDriver().getPageSource(); + const pageSourceStream: WriteStream = fs.createWriteStream(pageSourceFileName); + pageSourceStream.write(Buffer.from(pageSource), (): void => pageSourceStream.end()); + + // take browser console logs and write to file + const browserLogsEntries: logging.Entry[] = await this.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), (): void => { + browserLogsStream.end(); + }); + + // take networking logs and write to file + const networkLogsEntries: logging.Entry[] = await this.driverHelper.getDriver().manage().logs().get('performance'); + const events: any[] = networkLogsEntries.map((entry): any[] => JSON.parse(entry.message).message); + const har: any = chromeHar.harFromMessages(events, { includeTextFromResponseBody: true }); + this.redactHarContent(har); + + const networkLogsStream: WriteStream = fs.createWriteStream(harFileName); + networkLogsStream.write(Buffer.from(JSON.stringify(har)), (): void => { + networkLogsStream.end(); + }); + }); + } + + redactHarContent(har: any): void { + har.log?.entries?.forEach((entry: any): void => { + let text: string | undefined = entry.request?.postData?.text; + if (text) { + text = StringUtil.updateUrlQueryValue(text, 'csrf', ''); + text = StringUtil.updateUrlQueryValue(text, 'username', ''); + entry.request.postData.text = StringUtil.updateUrlQueryValue(text, 'password', ''); + } + + const cookies: any = entry.request?.cookies; + if (cookies) { + cookies.forEach((cookie: any): void => { + if (cookie.name?.startsWith('_oauth_proxy')) { + cookie.value = ''; + } + }); + } + + const headers: any = entry.request?.headers; + if (headers) { + headers.forEach((header: any): void => { + if (header.name?.toLowerCase() === 'cookie') { + header.value = StringUtil.updateCookieValue(header.value, '_oauth_proxy', ''); + header.value = StringUtil.updateCookieValue(header.value, '_oauth_proxy_csrf', ''); + } + }); + } + }); + } } export = CheReporter; diff --git a/tests/e2e/utils/CheReporter.ts.orig b/tests/e2e/utils/CheReporter.ts.orig new file mode 100644 index 00000000000..f6c4ab1f395 --- /dev/null +++ b/tests/e2e/utils/CheReporter.ts.orig @@ -0,0 +1,336 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import * as chromeHar from 'chrome-har'; +import * as mocha from 'mocha'; +import { CLASSES } from '../configs/inversify.types'; +import * as fs from 'fs'; +import { WriteStream } from 'fs'; +import * as rm from 'rimraf'; +import { logging } from 'selenium-webdriver'; +import { DriverHelper } from './DriverHelper'; +import { ScreenCatcher } from './ScreenCatcher'; +<<<<<<< HEAD +import { TimeoutConstants } from '../constants/TimeoutConstants'; +======= +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; +>>>>>>> main +import { Logger } from './Logger'; +import { StringUtil } from './StringUtil'; +<<<<<<< HEAD +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'; + +const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); +const screenCatcher: ScreenCatcher = e2eContainer.get(CLASSES.ScreenCatcher); +let methodIndex: number = 0; +let deleteScreencast: boolean = true; +======= +import { BASE_TEST_CONSTANTS } from '../constants/BASE_TEST_CONSTANTS'; +import { CHROME_DRIVER_CONSTANTS } from '../constants/CHROME_DRIVER_CONSTANTS'; +import { OAUTH_CONSTANTS } from '../constants/OAUTH_CONSTANTS'; +import { REPORTER_CONSTANTS } from '../constants/REPORTER_CONSTANTS'; +import { PLUGIN_TEST_CONSTANTS } from '../constants/PLUGIN_TEST_CONSTANTS'; +import { injectable } from 'inversify'; +import getDecorators from 'inversify-inject-decorators'; +import { e2eContainer } from '../configs/inversify.config'; + +const { lazyInject } = getDecorators(e2eContainer); +>>>>>>> main + +@injectable() +class CheReporter extends mocha.reporters.Spec { + private static methodIndex: number = 0; + private static deleteScreencast: boolean = true; + @lazyInject(CLASSES.DriverHelper) + private readonly driverHelper!: DriverHelper; + @lazyInject(CLASSES.ScreenCatcher) + private readonly screenCatcher!: ScreenCatcher; + +<<<<<<< HEAD + 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 ################## +>>>>>>> main + + 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} + +<<<<<<< HEAD + 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: ${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_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} + + ${process.env.TS_SELENIUM_PROXY_SERVER ? 'TS_SELENIUM_PROXY_SERVER: ' + process.env.TS_SELENIUM_PROXY_SERVER : ''} +>>>>>>> main + + 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} + +<<<<<<< HEAD + TS_SAMPLE_LIST: ${PluginsTestConstants.TS_SAMPLE_LIST} +======= + TS_SAMPLE_LIST: ${PLUGIN_TEST_CONSTANTS.TS_SAMPLE_LIST} +>>>>>>> main + + ${process.env.MOCHA_DIRECTORY ? 'MOCHA_DIRECTORY: ' + process.env.MOCHA_DIRECTORY : 'MOCHA_DIRECTORY is not set'} + ${process.env.USERSTORY ? 'USERSTORY: ' + process.env.USERSTORY : 'USERSTORY is not set'} +`; + +<<<<<<< HEAD + 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`; + } +======= + 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'; + } +>>>>>>> main + + launchInformation += '\n ######################################################## \n'; + + console.log(launchInformation); + +<<<<<<< HEAD + rm.sync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER); + }); + + runner.on('test', async function (test: mocha.Test): Promise { + if (!ReporterConstants.TS_SELENIUM_EXECUTION_SCREENCAST) { + return; + } +======= + rm.sync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + }); + + runner.on('test', async (test: mocha.Test): Promise => { + if (!REPORTER_CONSTANTS.TS_SELENIUM_EXECUTION_SCREENCAST) { + return; + } +>>>>>>> main + + CheReporter.methodIndex = CheReporter.methodIndex + 1; + const currentMethodIndex: number = CheReporter.methodIndex; + let iterationIndex: number = 1; + + while (!(test.state === 'passed' || test.state === 'failed')) { + await this.screenCatcher.catchMethodScreen(test.title, currentMethodIndex, iterationIndex); + iterationIndex = iterationIndex + 1; + +<<<<<<< HEAD + 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); + } + }); +======= + await this.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); + } + }); +>>>>>>> main + + runner.on('end', (): void => { + // delete screencast folder if conditions matched + if (CheReporter.deleteScreencast && REPORTER_CONSTANTS.DELETE_SCREENCAST_IF_TEST_PASS) { + rm.sync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + } + }); + + runner.on('fail', async (test: mocha.Test): Promise => { + Logger.error(`CheReporter runner.on.fail: ${test.fullTitle()} failed after ${test.duration}ms`); + // raise flag for keeping the screencast + CheReporter.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}`); + +<<<<<<< HEAD + // delete screencast folder if conditions matched + if (deleteScreencast && ReporterConstants.DELETE_SCREENCAST_IF_TEST_PASS) { + rm.sync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER); + } + }); +======= + 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`; + const harFileName: string = `${testReportDirPath}/har-${testTitle}.har`; +>>>>>>> main + + // 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); + } + +<<<<<<< HEAD + 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 dir for failed test report if not exist + const testReportDirExists: boolean = fs.existsSync(testReportDirPath); +>>>>>>> main + + if (!testReportDirExists) { + fs.mkdirSync(testReportDirPath); + } + +<<<<<<< HEAD + // 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); + } +======= + // take screenshot and write to file + const screenshot: string = await this.driverHelper.getDriver().takeScreenshot(); + const screenshotStream: WriteStream = fs.createWriteStream(screenshotFileName); + screenshotStream.write(Buffer.from(screenshot, 'base64'), (): void => screenshotStream.end()); + + // take page source and write to file + const pageSource: string = await this.driverHelper.getDriver().getPageSource(); + const pageSourceStream: WriteStream = fs.createWriteStream(pageSourceFileName); + pageSourceStream.write(Buffer.from(pageSource), (): void => pageSourceStream.end()); +>>>>>>> main + + // take browser console logs and write to file + const browserLogsEntries: logging.Entry[] = await this.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), (): void => { + browserLogsStream.end(); + }); + + // take networking logs and write to file + const networkLogsEntries: logging.Entry[] = await this.driverHelper.getDriver().manage().logs().get('performance'); + const events: any[] = networkLogsEntries.map((entry): any[] => JSON.parse(entry.message).message); + const har: any = chromeHar.harFromMessages(events, { includeTextFromResponseBody: true }); + this.redactHarContent(har); + + const networkLogsStream: WriteStream = fs.createWriteStream(harFileName); + networkLogsStream.write(Buffer.from(JSON.stringify(har)), (): void => { + networkLogsStream.end(); + }); + }); + } + + redactHarContent(har: any): void { + har.log?.entries?.forEach((entry: any): void => { + let text: string | undefined = entry.request?.postData?.text; + if (text) { + text = StringUtil.updateUrlQueryValue(text, 'csrf', ''); + text = StringUtil.updateUrlQueryValue(text, 'username', ''); + entry.request.postData.text = StringUtil.updateUrlQueryValue(text, 'password', ''); + } + + const cookies: any = entry.request?.cookies; + if (cookies) { + cookies.forEach((cookie: any): void => { + if (cookie.name?.startsWith('_oauth_proxy')) { + cookie.value = ''; + } + }); + } + +<<<<<<< HEAD + }); + } +======= + const headers: any = entry.request?.headers; + if (headers) { + headers.forEach((header: any): void => { + if (header.name?.toLowerCase() === 'cookie') { + header.value = StringUtil.updateCookieValue(header.value, '_oauth_proxy', ''); + header.value = StringUtil.updateCookieValue(header.value, '_oauth_proxy_csrf', ''); + } + }); + } + }); + } +>>>>>>> main +} + +export = CheReporter; diff --git a/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts b/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts index a09f949c75f..c2289ebd5ba 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,79 +14,97 @@ 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'; +import { injectable } from 'inversify'; +import { IContextParams } from './IContextParams'; +import { e2eContainer } from '../configs/inversify.config'; +import { CLASSES, EXTERNAL_CLASSES } from '../configs/inversify.types'; +import getDecorators from 'inversify-inject-decorators'; -/** - * to see more about IContextParams and generateDevfileContext(params) check README.md in "@eclipse-che/che-devworkspace-generator; - * tests/e2e/node_modules/@eclipse-che/che-devworkspace-generator/README.md - */ - -interface IContextParams { - devfilePath?: string | undefined; - devfileUrl?: string | undefined; - devfileContent?: string | undefined; - outputFile?: string | undefined; - editorPath?: string | undefined; - editorContent?: string | undefined; - editorEntry?: string | undefined; - pluginRegistryUrl?: string | undefined; - projects?: { - name: string; - location: string; - }[]; - injectDefaultComponent?: string | undefined; - defaultComponentImage?: string | undefined; -} +const { lazyInject } = getDecorators(e2eContainer); +@injectable() export class DevWorkspaceConfigurationHelper { - private generator: Generator = new Generator(); - private readonly params: IContextParams; + @lazyInject(EXTERNAL_CLASSES.Generator) + private readonly generator!: Generator; + @lazyInject(CLASSES.ShellExecutor) + private readonly shellExecutor!: ShellExecutor; + 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 (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 = this.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 + ); + } + + // write templates and then DevWorkspace in a single file + getDevWorkspaceConfigurationYamlAsString(context: DevfileContext): string { + Logger.debug(); - 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; - } + const allContentArray: any[] = context.devWorkspaceTemplates.map((template: V1alpha2DevWorkspaceTemplate): string => + YAML.stringify(template) + ); + allContentArray.push(YAML.stringify(context.devWorkspace)); - async generateDevfileContext(): Promise { - Logger.debug(`${this.constructor.name}.${this.generateDevfileContext.name}`); - if (!this.params.projects) { - this.params.projects = []; - } - return await this.generator.generateDevfileContext( - { - ...this.params, - projects: this.params.projects - }, - axios.default as any - ); - } + return allContentArray.join('---\n'); + } - // write templates and then DevWorkspace in a single file - async getDevWorkspaceConfigurationYamlAsString(context: DevfileContext): Promise { - Logger.debug(`${this.constructor.name}.${this.getDevWorkspaceConfigurationYamlAsString.name}`); - const allContentArray: any[] = context.devWorkspaceTemplates.map( - (template: V1alpha2DevWorkspaceTemplate) => YAML.stringify(template) - ); - allContentArray.push(YAML.stringify(context.devWorkspace)); + getDevWorkspaceConfigurationsAsYaml(allContentString: string): string { + Logger.debug(); + const content: any = {}; + const contentArray: string[] = allContentString.split('---\n'); + contentArray.forEach((e: any): void => { + e = YAML.parse(e); + e.kind === 'DevWorkspace' + ? (content.DevWorkspace = e) + : e.kind === 'DevWorkspaceTemplate' + ? (content.DevWorkspaceTemplate = e) + : Logger.error( + 'Problems with configuration parsing, string should be in format "DevWorkspace\\n---\\nDevWorkspaceTemplate"' + ); + }); - return allContentArray.join('---\n'); - } + return content; + } + patchDevWorkspaceConfigWithBuildContainerAttribute(devfileContextDevWorkspace: any): void { + Logger.debug(); + devfileContextDevWorkspace.spec.template.attributes = YAML.parse(` + controller.devfile.io/devworkspace-config: + name: devworkspace-config + namespace: openshift-devspaces + controller.devfile.io/scc: container-build + controller.devfile.io/storage-type: per-user`); + } } diff --git a/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts.orig b/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts.orig new file mode 100644 index 00000000000..f3f6f4cda38 --- /dev/null +++ b/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts.orig @@ -0,0 +1,139 @@ +/** ******************************************************************* + * 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'; +import YAML from 'yaml'; +import * as axios from 'axios'; +import { Logger } from './Logger'; +import { ShellExecutor } from './ShellExecutor'; +<<<<<<< HEAD +import { APITestConstants } from '../constants/APITestConstants'; +======= +import { API_TEST_CONSTANTS } from '../constants/API_TEST_CONSTANTS'; +import { injectable } from 'inversify'; +import { IContextParams } from './IContextParams'; +import { e2eContainer } from '../configs/inversify.config'; +import { CLASSES, EXTERNAL_CLASSES } from '../configs/inversify.types'; +import getDecorators from 'inversify-inject-decorators'; +>>>>>>> main + +const { lazyInject } = getDecorators(e2eContainer); + +@injectable() +export class DevWorkspaceConfigurationHelper { + @lazyInject(EXTERNAL_CLASSES.Generator) + private readonly generator!: Generator; + @lazyInject(CLASSES.ShellExecutor) + private readonly shellExecutor!: ShellExecutor; + private readonly params: IContextParams; + +<<<<<<< HEAD + 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 = this.shellExecutor.curl(API_TEST_CONSTANTS.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI).stdout; + } + this.params = params; + } +>>>>>>> main + + 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 + 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'); + } + + getDevWorkspaceConfigurationsAsYaml(allContentString: string): string { + Logger.debug(); + const content: any = {}; + const contentArray: string[] = allContentString.split('---\n'); + contentArray.forEach((e: any): void => { + e = YAML.parse(e); + e.kind === 'DevWorkspace' + ? (content.DevWorkspace = e) + : e.kind === 'DevWorkspaceTemplate' + ? (content.DevWorkspaceTemplate = e) + : Logger.error( + 'Problems with configuration parsing, string should be in format "DevWorkspace\\n---\\nDevWorkspaceTemplate"' + ); + }); + + return content; + } + patchDevWorkspaceConfigWithBuildContainerAttribute(devfileContextDevWorkspace: any): void { + Logger.debug(); + devfileContextDevWorkspace.spec.template.attributes = YAML.parse(` + controller.devfile.io/devworkspace-config: + name: devworkspace-config + namespace: openshift-devspaces + controller.devfile.io/scc: container-build + controller.devfile.io/storage-type: per-user`); + } +} diff --git a/tests/e2e/utils/DevfilesRegistryHelper.ts b/tests/e2e/utils/DevfilesRegistryHelper.ts index 1e1babf9158..74834be0c1d 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,114 @@ 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'; +import { injectable } from 'inversify'; +import { BASE_TEST_CONSTANTS, Platform } from '../constants/BASE_TEST_CONSTANTS'; +@injectable() export class DevfilesRegistryHelper { + async getInbuiltDevfilesRegistryContent(sampleNamePatterns?: string[]): Promise { + Logger.trace(); - async getInbuiltDevfilesRegistryContent(): Promise { - Logger.debug(`${this.constructor.name}.${this.getInbuiltDevfilesRegistryContent.name}`); - return await this.getContent(SupportedDevfilesRegistries.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL()); - } + return this.filterSamples( + sampleNamePatterns, + await this.getContent(SUPPORTED_DEVFILE_REGISTRIES.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL()) + ); + } - async getGitHubCheDevfileRegistryContent(): Promise { - Logger.debug(`${this.constructor.name}.${this.getGitHubCheDevfileRegistryContent.name}`); - return await this.getContent(SupportedDevfilesRegistries.GIT_HUB_CHE_DEVFILE_REGISTRY_URL); - } + async getGitHubCheDevfileRegistryContent(): Promise { + Logger.trace(); - async collectPathsToDevfilesFromRegistry(): Promise { - Logger.debug(`${this.constructor.name}.${this.collectPathsToDevfilesFromRegistry.name}`); - 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); } - }); + const url: string = + API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL() === '' + ? SUPPORTED_DEVFILE_REGISTRIES.GIT_HUB_CHE_DEVFILE_REGISTRY_URL + : API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL(); + return await this.getContent(url); + } - 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(`${this.constructor.name}.${this.collectPathsToDevfilesFromRegistry.name}: samples list: ${JSON.stringify(devfileSamples)}`); - } - break; - case (SupportedDevfilesRegistries.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL()): { - const content: any[any] = await this.getInbuiltDevfilesRegistryContent(); + async collectPathsToDevfilesFromRegistry(isInbuilt: boolean, sampleNamePatterns?: string[]): Promise { + Logger.debug(); - for (const sample of content) { - devfileSamples.push({name: sample.displayName, link: sample.links.v2}); - } - Logger.debug(`${this.constructor.name}.${this.collectPathsToDevfilesFromRegistry.name}: samples list: ${JSON.stringify(devfileSamples)}`); - } - break; - default: { - Logger.error(`${this.constructor.name}.${this.collectPathsToDevfilesFromRegistry.name}: unsupported registry url - ${APITestConstants.TS_API_ACCEPTANCE_TEST_REGISTRY_URL()}\n - supported registries: ${JSON.stringify(SupportedDevfilesRegistries)}`); - } - } - return devfileSamples; - } + const devfileSamples: object[] = []; + const sampleNames: string[] = []; + if (!isInbuilt) { + { + const content: any[any] = await this.getGitHubCheDevfileRegistryContent(); + content.forEach((e: any): void => { + if (e.name[0] !== '.') { + sampleNames.push(e.name); + } + }); - private async getContent(url: string, headers?: object): Promise { - Logger.debug(`${this.constructor.name}.${this.getContent.name}: ${url}`); + 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)}`); + } + } else if (isInbuilt) { + { + const content: any[any] = await this.getInbuiltDevfilesRegistryContent(sampleNamePatterns); + const devfileRegistryPrefix: string = + BASE_TEST_CONSTANTS.TS_PLATFORM === Platform.OPENSHIFT + ? BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL + '/devfile-registry' + : ''; + for (const sample of content) { + const linkToDevWorkspaceYaml: any = `${devfileRegistryPrefix}${sample.links.devWorkspaces['che-incubator/che-code/latest']}`; + devfileSamples.push({ + name: sample.displayName, + devWorkspaceConfigurationString: await this.getContent(linkToDevWorkspaceYaml) + }); + } + Logger.debug(`samples list: ${JSON.stringify(devfileSamples)}`); + } + } else { + { + Logger.error(`unsupported registry url - ${API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL()}\n + supported registries: ${JSON.stringify(SUPPORTED_DEVFILE_REGISTRIES)}`); + } + } + return devfileSamples; + } - let response: AxiosResponse | undefined; - try { - response = await axios.get(url, headers); - } catch (error) { - Logger.error(`${error} + ${url}`); - throw error; - } - return response?.data; - } + async getEditorContent(entry: string): Promise { + return await this.getContent(`${BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL}/${entry}`); + } + + private filterSamples(sampleNamePatterns: string[] | undefined, content: any): Promise { + if (sampleNamePatterns) { + const commonSampleNamePattern: RegExp = new RegExp(sampleNamePatterns.join('|'), 'i'); + content = content.filter((e: any): boolean => commonSampleNamePattern.test(e.displayName)); + } + return content; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private async getContent(url: string, headers?: object): Promise { + Logger.trace(`${url}`); + if (SUPPORTED_DEVFILE_REGISTRIES.TS_GIT_API_AUTH_TOKEN.length !== 0) { + /** + * if we use - https://api.github.com/repos/eclipse-che/che-devfile-registry/contents/devfiles/ URL + * for generating devfiles we can get a problem with rate limits to GitHub API, + * but we can pass auth. token for increase the limit and avoiding problems + */ + headers = { + headers: { Authorization: SUPPORTED_DEVFILE_REGISTRIES.TS_GIT_API_AUTH_TOKEN } + }; + } + 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/DevfilesRegistryHelper.ts.orig b/tests/e2e/utils/DevfilesRegistryHelper.ts.orig new file mode 100644 index 00000000000..2924decdf70 --- /dev/null +++ b/tests/e2e/utils/DevfilesRegistryHelper.ts.orig @@ -0,0 +1,156 @@ +/** ******************************************************************* + * 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 axios, { AxiosResponse } from 'axios'; +import { Logger } from './Logger'; +import YAML from 'yaml'; +<<<<<<< HEAD +import { APITestConstants, SupportedDevfilesRegistries } from '../constants/APITestConstants'; +======= +import { API_TEST_CONSTANTS, SUPPORTED_DEVFILE_REGISTRIES } from '../constants/API_TEST_CONSTANTS'; +import { injectable } from 'inversify'; +import { BASE_TEST_CONSTANTS, Platform } from '../constants/BASE_TEST_CONSTANTS'; +>>>>>>> main + +@injectable() +export class DevfilesRegistryHelper { + async getInbuiltDevfilesRegistryContent(sampleNamePatterns?: string[]): Promise { + Logger.trace(); + + return this.filterSamples( + sampleNamePatterns, + await this.getContent(SUPPORTED_DEVFILE_REGISTRIES.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL()) + ); + } + + async getGitHubCheDevfileRegistryContent(): Promise { + Logger.trace(); + +<<<<<<< HEAD + async collectPathsToDevfilesFromRegistry(): Promise { + Logger.debug(`${this.constructor.name}.${this.collectPathsToDevfilesFromRegistry.name}`); + 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); } + }); +======= + const url: string = + API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL() === '' + ? SUPPORTED_DEVFILE_REGISTRIES.GIT_HUB_CHE_DEVFILE_REGISTRY_URL + : API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL(); + return await this.getContent(url); + } +>>>>>>> main + + async collectPathsToDevfilesFromRegistry(isInbuilt: boolean, sampleNamePatterns?: string[]): Promise { + Logger.debug(); + +<<<<<<< HEAD + for (const sample of content) { + devfileSamples.push({name: sample.displayName, link: sample.links.v2}); + } + Logger.debug(`${this.constructor.name}.${this.collectPathsToDevfilesFromRegistry.name}: samples list: ${JSON.stringify(devfileSamples)}`); + } + break; + default: { + Logger.error(`${this.constructor.name}.${this.collectPathsToDevfilesFromRegistry.name}: unsupported registry url - ${APITestConstants.TS_API_ACCEPTANCE_TEST_REGISTRY_URL()}\n + supported registries: ${JSON.stringify(SupportedDevfilesRegistries)}`); + } + } + return devfileSamples; + } +======= + const devfileSamples: object[] = []; + const sampleNames: string[] = []; + if (!isInbuilt) { + { + const content: any[any] = await this.getGitHubCheDevfileRegistryContent(); + content.forEach((e: any): void => { + if (e.name[0] !== '.') { + sampleNames.push(e.name); + } + }); +>>>>>>> main + + 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)}`); + } + } else if (isInbuilt) { + { + const content: any[any] = await this.getInbuiltDevfilesRegistryContent(sampleNamePatterns); + const devfileRegistryPrefix: string = + BASE_TEST_CONSTANTS.TS_PLATFORM === Platform.OPENSHIFT + ? BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL + '/devfile-registry' + : ''; + for (const sample of content) { + const linkToDevWorkspaceYaml: any = `${devfileRegistryPrefix}${sample.links.devWorkspaces['che-incubator/che-code/latest']}`; + devfileSamples.push({ + name: sample.displayName, + devWorkspaceConfigurationString: await this.getContent(linkToDevWorkspaceYaml) + }); + } + Logger.debug(`samples list: ${JSON.stringify(devfileSamples)}`); + } + } else { + { + Logger.error(`unsupported registry url - ${API_TEST_CONSTANTS.TS_API_ACCEPTANCE_TEST_REGISTRY_URL()}\n + supported registries: ${JSON.stringify(SUPPORTED_DEVFILE_REGISTRIES)}`); + } + } + return devfileSamples; + } + + async getEditorContent(entry: string): Promise { + return await this.getContent(`${BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL}/${entry}`); + } + + private filterSamples(sampleNamePatterns: string[] | undefined, content: any): Promise { + if (sampleNamePatterns) { + const commonSampleNamePattern: RegExp = new RegExp(sampleNamePatterns.join('|'), 'i'); + content = content.filter((e: any): boolean => commonSampleNamePattern.test(e.displayName)); + } + return content; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + private async getContent(url: string, headers?: object): Promise { + Logger.trace(`${url}`); + if (SUPPORTED_DEVFILE_REGISTRIES.TS_GIT_API_AUTH_TOKEN.length !== 0) { + /** + * if we use - https://api.github.com/repos/eclipse-che/che-devfile-registry/contents/devfiles/ URL + * for generating devfiles we can get a problem with rate limits to GitHub API, + * but we can pass auth. token for increase the limit and avoiding problems + */ + headers = { + headers: { Authorization: SUPPORTED_DEVFILE_REGISTRIES.TS_GIT_API_AUTH_TOKEN } + }; + } + 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 a5f90028482..f94a6796133 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,706 +13,739 @@ 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('DriverHelper.getAction'); - - return this.driver.actions(); - } - - async isVisible(locator: By): Promise { - Logger.trace(`DriverHelper.isVisible ${locator}`); - - try { - const element: WebElement = await this.driver.findElement(locator); - return await element.isDisplayed(); - } catch { - return false; - } - } - - async wait(milliseconds: number): Promise { - Logger.trace(`DriverHelper.wait (${milliseconds} milliseconds)`); - - await this.driver.sleep(milliseconds); - } - - async refreshPage(): Promise { - Logger.trace(`DriverHelper.refreshPage`); - - 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(`DriverHelper.waitVisibilityBoolean ${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(`DriverHelper.waitDisappearanceBoolean ${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(`DriverHelper.waitVisibility ${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(`DriverHelper.waitVisibility - 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(`DriverHelper.waitVisibility - 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(`DriverHelper.waitVisibility - failed with NoSuchWindow exception. Attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.waitVisibility - failed with an unexpected exception - ${err}`); - throw err; - } - - try { - const visibleWebElement: WebElement = await this.driver.wait(until.elementIsVisible(element), polling); - Logger.trace('DriverHelper.waitVisibility - 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(`DriverHelper.waitVisibility - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - } - continue; - } - - if (err instanceof error.StaleElementReferenceError) { - Logger.debug(`DriverHelper.waitVisibility - Stale element error - ${err}`); - await this.wait(polling); - continue; - } - - Logger.error(`DriverHelper.waitVisibility - failed with an unexpected exception - ${err}`); - throw err; - } - } - - throw new error.TimeoutError(`Exceeded maximum visibility checkings 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(`DriverHelper.waitPresence ${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(`DriverHelper.waitPresence - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`DriverHelper.waitPresence - 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(`DriverHelper.waitAllPresence ${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(`DriverHelper.waitAllPresence - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - if (err instanceof error.StaleElementReferenceError) { - await this.wait(polling); - continue; - } - - Logger.error(`DriverHelper.waitAllPresence - 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(`DriverHelper.waitAllVisibility ${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(`DriverHelper.waitDisappearance ${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(`DriverHelper.waitDisappearanceWithTimeout ${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(`DriverHelper.waitAllDisappearance ${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(`DriverHelper.waitAndClick ${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(`DriverHelper.waitAndClick - failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`DriverHelper.waitAndClick - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.waitAndClick - 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(`DriverHelper.waitAndClick - ${elementLocator} - ${err}`); - await this.wait(polling); - continue; - } - - if (isElementClickInterceptedOnLastAttempt(err, i)) { - Logger.debug(`DriverHelper.waitAndClick - Element is not clickable, try to perform pointer click`); - await this.getAction() - .move({ - origin: await this.waitPresence(elementLocator) - }) - .click() - .perform(); - return; - } - - Logger.error(`DriverHelper.waitAndClick - failed with an unexpected exception - ${err}`); - throw err; - } - } - - 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(`DriverHelper.waitAndGetElementAttribute ${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(`DriverHelper.waitAndGetElementAttribute - failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`DriverHelper.waitAndGetElementAttribute - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.waitAndGetElementAttribute - 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(`DriverHelper.waitAndGetElementAttribute - 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(`DriverHelper.waitAndGetCssValue ${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(`DriverHelper.waitAndGetCssValue - failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`DriverHelper.waitAndGetCssValue - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.waitAndGetCssValue - 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(`DriverHelper.waitAndGetCssValue - 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(`DriverHelper.waitAttributeValue ${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(`DriverHelper.type ${elementLocator} text: ***`); - } else { - Logger.trace(`DriverHelper.type ${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(`DriverHelper.type - failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`DriverHelper.type - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.type - 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(`DriverHelper.type - 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(`DriverHelper.typeToInvisible ${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(`DriverHelper.typeToInvisible - failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`DriverHelper.typeToInvisible - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.typeToInvisible - 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(`DriverHelper.typeToInvisible - 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(`DriverHelper.clear ${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(`DriverHelper.clear - failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`DriverHelper.clear - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.clear - 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(`DriverHelper.clear - 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(`DriverHelper.clearInvisible ${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(`DriverHelper.clearInvisible - failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`DriverHelper.clearInvisible - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.clearInvisible - 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(`DriverHelper.clearInvisible - 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(`DriverHelper.enterValue ${elementLocator} text: ***`); - } else { - Logger.trace(`DriverHelper.enterValue ${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(`DriverHelper.waitAndSwitchToFrame ${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(`DriverHelper.waitAndGetText ${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(`DriverHelper.waitAndGetText - failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`DriverHelper.waitAndGetText - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.waitAndGetText - 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(`DriverHelper.waitAndGetText - 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(`DriverHelper.waitAndGetValue ${elementLocator}`); - - return await this.waitAndGetElementAttribute(elementLocator, 'value', timeout); - } - - async waitUntilTrue(callback: any, timeout: number): Promise { - Logger.trace('DriverHelper.waitUntilTrue'); - - 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(`DriverHelper.scrollTo ${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(`DriverHelper.scrollTo - failed with exception, out of attempts - ${err}`); - throw err; - } - - if (err instanceof error.TimeoutError) { - Logger.trace(`DriverHelper.scrollTo - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); - continue; - } - - Logger.error(`DriverHelper.scrollTo - 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(`DriverHelper.scrollTo - 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('DriverHelper.getDriver'); - - 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 = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): 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: any, 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 getting 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 { + Logger.trace(); + + 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 { + Logger.trace(); + + await this.scrollTo(elementLocator, timeout); + await this.enterValue(elementLocator, value, timeout); + } + + // method is useful to debug page object elements + async highLightElement(element: WebElement): Promise { + Logger.trace(); + + await this.getDriver().executeScript('arguments[0].style.border="2px solid red"', element); + } + + getDriver(): ThenableWebDriver { + Logger.trace(); + + return this.driver; + } + + async navigateToUrl(url: string): Promise { + Logger.trace(); + + await this.getDriver().navigate().to(url); + } + + async quit(): Promise { + Logger.trace(); + + await this.getDriver().quit(); + } } diff --git a/tests/e2e/utils/DriverHelper.ts.orig b/tests/e2e/utils/DriverHelper.ts.orig new file mode 100644 index 00000000000..84f4d4e0fdb --- /dev/null +++ b/tests/e2e/utils/DriverHelper.ts.orig @@ -0,0 +1,1451 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { IDriver } from '../driver/IDriver'; +import { inject, injectable } from 'inversify'; +import { TYPES } from '../configs/inversify.types'; +import { Actions, By, error, ThenableWebDriver, until, WebElement } from 'selenium-webdriver'; +import 'reflect-metadata'; +import { Logger } from './Logger'; +import { TIMEOUT_CONSTANTS } from '../constants/TIMEOUT_CONSTANTS'; + +@injectable() +export class DriverHelper { +<<<<<<< HEAD + private readonly driver: ThenableWebDriver; + + constructor(@inject(TYPES.Driver) driver: IDriver) { + this.driver = driver.get() as ThenableWebDriver; + } + + getAction(): Actions { + Logger.trace('DriverHelper.getAction'); + + return this.driver.actions(); + } + + async isVisible(locator: By): Promise { + Logger.trace(`DriverHelper.isVisible ${locator}`); + + try { + const element: WebElement = await this.driver.findElement(locator); + return await element.isDisplayed(); + } catch { + return false; + } + } + + async wait(milliseconds: number): Promise { + Logger.trace(`DriverHelper.wait (${milliseconds} milliseconds)`); + + await this.driver.sleep(milliseconds); + } + + async refreshPage(): Promise { + Logger.trace(`DriverHelper.refreshPage`); + + 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(`DriverHelper.waitVisibilityBoolean ${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(`DriverHelper.waitDisappearanceBoolean ${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(`DriverHelper.waitVisibility ${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(`DriverHelper.waitVisibility - 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(`DriverHelper.waitVisibility - 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(`DriverHelper.waitVisibility - failed with NoSuchWindow exception. Attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.waitVisibility - failed with an unexpected exception - ${err}`); + throw err; + } + + try { + const visibleWebElement: WebElement = await this.driver.wait(until.elementIsVisible(element), polling); + Logger.trace('DriverHelper.waitVisibility - 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(`DriverHelper.waitVisibility - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + } + continue; + } + + if (err instanceof error.StaleElementReferenceError) { + Logger.debug(`DriverHelper.waitVisibility - Stale element error - ${err}`); + await this.wait(polling); + continue; + } + + Logger.error(`DriverHelper.waitVisibility - failed with an unexpected exception - ${err}`); + throw err; + } + } + + throw new error.TimeoutError(`Exceeded maximum visibility checkings 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(`DriverHelper.waitPresence ${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(`DriverHelper.waitPresence - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`DriverHelper.waitPresence - 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(`DriverHelper.waitAllPresence ${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(`DriverHelper.waitAllPresence - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + if (err instanceof error.StaleElementReferenceError) { + await this.wait(polling); + continue; + } + + Logger.error(`DriverHelper.waitAllPresence - 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(`DriverHelper.waitAllVisibility ${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(`DriverHelper.waitDisappearance ${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(`DriverHelper.waitDisappearanceWithTimeout ${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(`DriverHelper.waitAllDisappearance ${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(`DriverHelper.waitAndClick ${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(`DriverHelper.waitAndClick - failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`DriverHelper.waitAndClick - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.waitAndClick - 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(`DriverHelper.waitAndClick - ${elementLocator} - ${err}`); + await this.wait(polling); + continue; + } + + if (isElementClickInterceptedOnLastAttempt(err, i)) { + Logger.debug(`DriverHelper.waitAndClick - Element is not clickable, try to perform pointer click`); + await this.getAction() + .move({ + origin: await this.waitPresence(elementLocator) + }) + .click() + .perform(); + return; + } + + Logger.error(`DriverHelper.waitAndClick - failed with an unexpected exception - ${err}`); + throw err; + } + } + + 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(`DriverHelper.waitAndGetElementAttribute ${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(`DriverHelper.waitAndGetElementAttribute - failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`DriverHelper.waitAndGetElementAttribute - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.waitAndGetElementAttribute - 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(`DriverHelper.waitAndGetElementAttribute - 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(`DriverHelper.waitAndGetCssValue ${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(`DriverHelper.waitAndGetCssValue - failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`DriverHelper.waitAndGetCssValue - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.waitAndGetCssValue - 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(`DriverHelper.waitAndGetCssValue - 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(`DriverHelper.waitAttributeValue ${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(`DriverHelper.type ${elementLocator} text: ***`); + } else { + Logger.trace(`DriverHelper.type ${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(`DriverHelper.type - failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`DriverHelper.type - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.type - 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(`DriverHelper.type - 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(`DriverHelper.typeToInvisible ${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(`DriverHelper.typeToInvisible - failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`DriverHelper.typeToInvisible - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.typeToInvisible - 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(`DriverHelper.typeToInvisible - 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(`DriverHelper.clear ${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(`DriverHelper.clear - failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`DriverHelper.clear - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.clear - 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(`DriverHelper.clear - 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(`DriverHelper.clearInvisible ${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(`DriverHelper.clearInvisible - failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`DriverHelper.clearInvisible - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.clearInvisible - 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(`DriverHelper.clearInvisible - 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(`DriverHelper.enterValue ${elementLocator} text: ***`); + } else { + Logger.trace(`DriverHelper.enterValue ${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(`DriverHelper.waitAndSwitchToFrame ${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(`DriverHelper.waitAndGetText ${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(`DriverHelper.waitAndGetText - failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`DriverHelper.waitAndGetText - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.waitAndGetText - 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(`DriverHelper.waitAndGetText - 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(`DriverHelper.waitAndGetValue ${elementLocator}`); + + return await this.waitAndGetElementAttribute(elementLocator, 'value', timeout); + } + + async waitUntilTrue(callback: any, timeout: number): Promise { + Logger.trace('DriverHelper.waitUntilTrue'); + + 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(`DriverHelper.scrollTo ${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(`DriverHelper.scrollTo - failed with exception, out of attempts - ${err}`); + throw err; + } + + if (err instanceof error.TimeoutError) { + Logger.trace(`DriverHelper.scrollTo - Polling timed out attempt #${(i + 1)}, retrying with ${polling}ms timeout`); + continue; + } + + Logger.error(`DriverHelper.scrollTo - 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(`DriverHelper.scrollTo - 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('DriverHelper.getDriver'); + + 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 = TIMEOUT_CONSTANTS.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): 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: any, 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 getting 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 { + Logger.trace(); + + 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 { + Logger.trace(); + + await this.scrollTo(elementLocator, timeout); + await this.enterValue(elementLocator, value, timeout); + } + + // method is useful to debug page object elements + async highLightElement(element: WebElement): Promise { + Logger.trace(); + + await this.getDriver().executeScript('arguments[0].style.border="2px solid red"', element); + } + + getDriver(): ThenableWebDriver { + Logger.trace(); + + return this.driver; + } + + async navigateToUrl(url: string): Promise { + Logger.trace(); + + await this.getDriver().navigate().to(url); + } + + async quit(): Promise { + Logger.trace(); + + await this.getDriver().quit(); + } +>>>>>>> main +} diff --git a/tests/e2e/utils/IContextParams.ts b/tests/e2e/utils/IContextParams.ts new file mode 100644 index 00000000000..22e8dfbf3f3 --- /dev/null +++ b/tests/e2e/utils/IContextParams.ts @@ -0,0 +1,26 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +export interface IContextParams { + devfilePath?: string | undefined; + devfileUrl?: string | undefined; + devfileContent?: string | undefined; + outputFile?: string | undefined; + editorPath?: string | undefined; + editorContent?: string | undefined; + editorEntry?: string | undefined; + pluginRegistryUrl?: string | undefined; + projects?: { + name: string; + location: string; + }[]; + injectDefaultComponent?: string | undefined; + defaultComponentImage?: string | undefined; +} diff --git a/tests/e2e/utils/IKubernetesCommandLineToolsExecutor.ts b/tests/e2e/utils/IKubernetesCommandLineToolsExecutor.ts new file mode 100644 index 00000000000..1b5d976b824 --- /dev/null +++ b/tests/e2e/utils/IKubernetesCommandLineToolsExecutor.ts @@ -0,0 +1,42 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { ShellString } from 'shelljs'; + +export interface IKubernetesCommandLineToolsExecutor { + loginToOcp(): void; + + getContainerName(): string; + + getWorkspacePodName(): string; + + deleteDevWorkspace(): void; + + applyAndWaitDevWorkspace(yamlConfiguration: string): ShellString; + + execInContainerCommand(commandToExecute: string, container: string): ShellString; + + applyYamlConfigurationAsStringOutput(yamlConfiguration: string): ShellString; + + applyYamlConfigurationAsFile(pathToFile: string): void; + + getDevWorkspaceYamlConfiguration(): ShellString; + + waitDevWorkspace(timeout: number): ShellString; + + createProject(projectName: string): void; + + deleteProject(projectName: string): void; + + getPodAndContainerNames(): void; + + isUserLoggedIn(user: string): boolean; + + getServerUrl(): string; +} diff --git a/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts b/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts index bfd0c5bce65..ae55ebddb75 100644 --- a/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts +++ b/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts @@ -1,182 +1,240 @@ +/** ******************************************************************* + * 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'; - -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.getLoggingName(this.loginToOcp.name)}: Login to the "OC" client.`); - const url: string = this.getServerUrl(); - if (this.isUserLoggedIn()) { - Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: User already logged`); - } else { - Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: 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.getLoggingName(this.loginToOcp.name)}: doesn't support login command`); - } - } - - getContainerName(): string { - Logger.debug(`${this.getLoggingName(this.getContainerName.name)}: 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.getLoggingName(this.getWorkspacePodName.name)}: 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.getLoggingName(this.deleteDevWorkspace.name)}: 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.getLoggingName(this.executeCommand.name)}:`); - 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.getLoggingName(this.applyYamlConfigurationAsStringOutput.name)}:`); - return ShellExecutor.execWithLog(`cat < 0) { + this._namespace = BASE_TEST_CONSTANTS.TEST_NAMESPACE; + } else if (!this._namespace) { + const applicationName: string = BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME(); + if (applicationName === 'default') { + this._namespace = applicationName; + } else { + this._namespace = OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME + '-' + applicationName; + } + } + return this._namespace; + } + + // login to Openshift cluster with username and password + loginToOcp(user: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME, password: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD): void { + if (this.kubernetesCommandLineTool === KubernetesCommandLineTool.OC) { + Logger.debug(`${this.kubernetesCommandLineTool} - login to the "OC" client.`); + const url: string = this.getServerUrl(); + if (this.isUserLoggedIn(user)) { + Logger.debug(`${this.kubernetesCommandLineTool} - user already logged`); + } else { + Logger.debug(`${this.kubernetesCommandLineTool} - login ${url}, ${user}`); + exec(`oc login --server=${url} -u=${user} -p=${password} --insecure-skip-tls-verify`); + } + } else { + Logger.debug(`${this.kubernetesCommandLineTool} - doesn't support login command`); + } + } + + getContainerName(): string { + Logger.debug(`${this.kubernetesCommandLineTool} - get container name.`); + + const output: ShellString = this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} get ${KubernetesCommandLineToolsExecutor.pod} -o jsonpath='{.spec.containers[*].name}' -n ${this.namespace}` + ); + echo('\n'); + return output.stderr ? output.stderr : output.stdout; + } + + getWorkspacePodName(): string { + Logger.debug(`${this.kubernetesCommandLineTool} - get workspace pod name.`); + + const output: ShellString = this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} get pod -l controller.devfile.io/devworkspace_name=${this.workspaceName} -n ${this.namespace} -o name` + ); + return output.stderr ? output.stderr : output.stdout.replace('\n', ''); + } + + deleteDevWorkspace(): void { + Logger.debug(`${this.kubernetesCommandLineTool} - delete '${this.workspaceName}' workspace`); + + this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} patch dw ${this.workspaceName} -n ${this.namespace} -p '{ "metadata": { "finalizers": null }}' --type merge || true` + ); + this.shellExecutor.executeCommand(`${this.kubernetesCommandLineTool} delete dw ${this.workspaceName} -n ${this.namespace} || true`); + this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} delete dwt ${BASE_TEST_CONSTANTS.TS_SELENIUM_EDITOR}-${this.workspaceName} -n ${this.namespace} || true` + ); + } + + applyAndWaitDevWorkspace(yamlConfiguration: string): ShellString { + Logger.debug(`${this.kubernetesCommandLineTool}`); + + if (this.kubernetesCommandLineTool === KubernetesCommandLineTool.KUBECTL) { + this.createNamespace(); + } + this.applyYamlConfigurationAsStringOutput(yamlConfiguration); + return this.waitDevWorkspace(); + } + + execInContainerCommand(commandToExecute: string, container: string = KubernetesCommandLineToolsExecutor.container): ShellString { + Logger.debug(`${this.kubernetesCommandLineTool}`); + + return this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} exec -i ${KubernetesCommandLineToolsExecutor.pod} -n ${this.namespace} -c ${container} -- sh -c '${commandToExecute}'` + ); + } + + applyYamlConfigurationAsStringOutput(yamlConfiguration: string): ShellString { + Logger.debug(`${this.kubernetesCommandLineTool}`); + + return this.shellExecutor.executeCommand( + `cat <>>>>>> main + + constructor( + @inject(CLASSES.ShellExecutor) + protected readonly shellExecutor: ShellExecutor + ) { + this.kubernetesCommandLineTool = API_TEST_CONSTANTS.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL; + } + + set namespace(value: string | undefined) { + this._namespace = value; + } + + set workspaceName(value: string | undefined) { + this._workspaceName = value; + } + +<<<<<<< HEAD + // login to Openshift cluster with username and password + loginToOcp(): void { + if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.OC) { + Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: Login to the "OC" client.`); + const url: string = this.getServerUrl(); + if (this.isUserLoggedIn()) { + Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: User already logged`); + } else { + Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: 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.getLoggingName(this.loginToOcp.name)}: doesn't support login command`); + } + } +======= + get workspaceName(): string | undefined { + return this._workspaceName; + } +>>>>>>> main + + get namespace(): string | undefined { + if (BASE_TEST_CONSTANTS.TEST_NAMESPACE.length > 0) { + this._namespace = BASE_TEST_CONSTANTS.TEST_NAMESPACE; + } else if (!this._namespace) { + const applicationName: string = BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME(); + if (applicationName === 'default') { + this._namespace = applicationName; + } else { + this._namespace = OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME + '-' + applicationName; + } + } + return this._namespace; + } + + // login to Openshift cluster with username and password + loginToOcp(user: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_USERNAME, password: string = OAUTH_CONSTANTS.TS_SELENIUM_OCP_PASSWORD): void { + if (this.kubernetesCommandLineTool === KubernetesCommandLineTool.OC) { + Logger.debug(`${this.kubernetesCommandLineTool} - login to the "OC" client.`); + const url: string = this.getServerUrl(); + if (this.isUserLoggedIn(user)) { + Logger.debug(`${this.kubernetesCommandLineTool} - user already logged`); + } else { + Logger.debug(`${this.kubernetesCommandLineTool} - login ${url}, ${user}`); + exec(`oc login --server=${url} -u=${user} -p=${password} --insecure-skip-tls-verify`); + } + } else { + Logger.debug(`${this.kubernetesCommandLineTool} - doesn't support login command`); + } + } + +<<<<<<< HEAD + deleteDevWorkspace(): void { + Logger.debug(`${this.getLoggingName(this.deleteDevWorkspace.name)}: 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`); + } +======= + getContainerName(): string { + Logger.debug(`${this.kubernetesCommandLineTool} - get container name.`); +>>>>>>> main + + const output: ShellString = this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} get ${KubernetesCommandLineToolsExecutor.pod} -o jsonpath='{.spec.containers[*].name}' -n ${this.namespace}` + ); + echo('\n'); + return output.stderr ? output.stderr : output.stdout; + } + + getWorkspacePodName(): string { + Logger.debug(`${this.kubernetesCommandLineTool} - get workspace pod name.`); + + const output: ShellString = this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} get pod -l controller.devfile.io/devworkspace_name=${this.workspaceName} -n ${this.namespace} -o name` + ); + return output.stderr ? output.stderr : output.stdout.replace('\n', ''); + } + + deleteDevWorkspace(): void { + Logger.debug(`${this.kubernetesCommandLineTool} - delete '${this.workspaceName}' workspace`); + + this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} patch dw ${this.workspaceName} -n ${this.namespace} -p '{ "metadata": { "finalizers": null }}' --type merge || true` + ); + this.shellExecutor.executeCommand(`${this.kubernetesCommandLineTool} delete dw ${this.workspaceName} -n ${this.namespace} || true`); + this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} delete dwt ${BASE_TEST_CONSTANTS.TS_SELENIUM_EDITOR}-${this.workspaceName} -n ${this.namespace} || true` + ); + } + + applyAndWaitDevWorkspace(yamlConfiguration: string): ShellString { + Logger.debug(`${this.kubernetesCommandLineTool}`); + + if (this.kubernetesCommandLineTool === KubernetesCommandLineTool.KUBECTL) { + this.createNamespace(); + } + this.applyYamlConfigurationAsStringOutput(yamlConfiguration); + return this.waitDevWorkspace(); + } + + execInContainerCommand(commandToExecute: string, container: string = KubernetesCommandLineToolsExecutor.container): ShellString { + Logger.debug(`${this.kubernetesCommandLineTool}`); + + return this.shellExecutor.executeCommand( + `${this.kubernetesCommandLineTool} exec -i ${KubernetesCommandLineToolsExecutor.pod} -n ${this.namespace} -c ${container} -- sh -c '${commandToExecute}'` + ); + } + + applyYamlConfigurationAsStringOutput(yamlConfiguration: string): ShellString { + Logger.debug(`${this.kubernetesCommandLineTool}`); + + return this.shellExecutor.executeCommand( + `cat <>>>>>> main + + return this.shellExecutor.executeCommand( + `cat <>>>>>> main +} + +@injectable() +export class ContainerTerminal extends KubernetesCommandLineToolsExecutor { + constructor( + @inject(CLASSES.ShellExecutor) + readonly shellExecutor: ShellExecutor, + @inject(CLASSES.KubernetesCommandLineToolsExecutor) + readonly cluster: KubernetesCommandLineToolsExecutor + ) { + super(shellExecutor); + } + + ls(path: string = ''): ShellString { + return this.execInContainerCommand('ls ' + path); + } + + pwd(): ShellString { + return this.execInContainerCommand('pwd'); + } + + cd(path: string): ShellString { + return this.execInContainerCommand('cd ' + path); + } + + gitClone(repository: string): ShellString { + return this.execInContainerCommand('git clone ' + repository); + } + + removeFolder(path: string): ShellString { + return this.execInContainerCommand('rm -rf ' + path); + } +} diff --git a/tests/e2e/utils/Logger.ts b/tests/e2e/utils/Logger.ts index 55a9ed1e1d4..d67c6cc8583 100644 --- a/tests/e2e/utils/Logger.ts +++ b/tests/e2e/utils/Logger.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 @@ -7,85 +7,152 @@ * * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { ReporterConstants } from '../constants/ReporterConstants'; +import { REPORTER_CONSTANTS } from '../constants/REPORTER_CONSTANTS'; +import { rpApi } from '../specs/MochaHooks'; -export abstract class Logger { +export class Logger { + /** + * uses for logging of fatal errors. + * @param text log text + * @param indentLevel log level + */ - /** - * Uses for logging of fatal errors. - * @param text log text - * @param indentLevel log level - */ - static error(text: string, indentLevel: number = 1): void { - this.logText(indentLevel, `[ERROR] ${text}`); - } + static error(text: string = '', indentLevel: number = 1): void { + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '[ERROR] '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.error(message); + } + } - /** - * Uses for logging of recoverable errors and general warnings. - * @param text log text - * @param indentLevel log level - */ - static warn(text: string, indentLevel: number = 1): void { - if (ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR') { - return; - } - this.logText(indentLevel, `[WARN] ${text}`); - } + /** + * uses for logging of recoverable errors and general warnings. + * @param text log text + * @param indentLevel log level + */ + static warn(text: string = '', indentLevel: number = 1): void { + if (REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'ERROR') { + return; + } + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '[WARN] '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.warn(message); + } + } - /** - * Uses for logging of the public methods of the pageobjects. - * @param text log text - * @param indentLevel log level - */ - static info(text: string, indentLevel: number = 3): void { - if (ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR' || - ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'WARN') { - return; - } - this.logText(indentLevel, `• ${text}`); - } + /** + * uses for logging of the public methods of the pageobjects. + * @param text log text + * @param indentLevel log level + */ + static info(text: string = '', indentLevel: number = 3): void { + if (REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'ERROR' || REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'WARN') { + return; + } + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '• '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.info(message); + } + } - /** - * Uses for logging of the public methods of the pageobjects. - * @param text log text - * @param indentLevel log level - */ - static debug(text: string, indentLevel: number = 5): void { - if (ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR' || - ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'WARN' || - ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'INFO') { - return; - } - this.logText(indentLevel, `▼ ${text}`); - } + /** + * uses for logging of the public methods of the pageobjects. + * @param text log text + * @param indentLevel log level + */ + static debug(text: string = '', indentLevel: number = 5): void { + if ( + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'ERROR' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'WARN' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'INFO' + ) { + return; + } + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '▼ '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.debug(message); + } + } - /** - * Uses for logging of the public methods of the {@link DriverHelper} or - * private methods inside of pageobjects. - * @param text log text - * @param indentLevel log level - */ - static trace(text: string, indentLevel: number = 6): void { - if (ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR' || - ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'WARN' || - ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'INFO' || - ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'DEBUG') { - return; - } - this.logText(indentLevel, `‣ ${text}`); - } + /** + * uses for logging of the public methods of the {@link DriverHelper} or + * private methods inside of pageobjects. + * @param text log text + * @param indentLevel log level + */ + static trace(text: string = '', indentLevel: number = 6): void { + if ( + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'ERROR' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'WARN' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'INFO' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'DEBUG' + ) { + return; + } + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '‣ '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.trace(message); + } + } - private static logText(messageIndentationLevel: number, text: string): void { - // start group for every level - for (let i: number = 0; i < messageIndentationLevel; i++) { - console.group(); - } - // print the trimmed text - // if multiline, the message should be properly padded - console.log(text); - // end group for every level - for (let i: number = 0; i < messageIndentationLevel; i++) { - console.groupEnd(); - } - } + private static getFullMessage(callerInfo: string, text: string): string { + return `${callerInfo}${this.separator(text, callerInfo)}${text}`; + } + + private static separator(text: string, caller: string): string { + return text ? (caller ? ' - ' : '') : ''; + } + + private static logText(messageIndentationLevel: number, logLevelSymbol: string, text: string): void { + if (text) { + // start group for every level + for (let i: number = 0; i < messageIndentationLevel; i++) { + console.group(); + } + // print the trimmed text + // if multiline, the message should be properly padded + console.log(logLevelSymbol + text); + // end group for every level + for (let i: number = 0; i < messageIndentationLevel; i++) { + console.groupEnd(); + } + } + } + + private static getCallerInfo(i: number = 4): string { + const stack: string[] = this.getCallStackArray(); + // " at functionName ( ..." => "functionName" + return stack[i].includes('. { + return acc || /MochaHooks|CheReporter/.test(e); + }, false); + } } diff --git a/tests/e2e/utils/Logger.ts.orig b/tests/e2e/utils/Logger.ts.orig new file mode 100644 index 00000000000..1a08ac86866 --- /dev/null +++ b/tests/e2e/utils/Logger.ts.orig @@ -0,0 +1,224 @@ +<<<<<<< HEAD +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. +======= +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. +>>>>>>> main + * + * 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 + **********************************************************************/ +<<<<<<< HEAD +import { ReporterConstants } from '../constants/ReporterConstants'; +======= +import { REPORTER_CONSTANTS } from '../constants/REPORTER_CONSTANTS'; +import { rpApi } from '../specs/MochaHooks'; +>>>>>>> main + +export class Logger { + /** + * uses for logging of fatal errors. + * @param text log text + * @param indentLevel log level + */ + + static error(text: string = '', indentLevel: number = 1): void { + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '[ERROR] '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.error(message); + } + } + +<<<<<<< HEAD + /** + * Uses for logging of recoverable errors and general warnings. + * @param text log text + * @param indentLevel log level + */ + static warn(text: string, indentLevel: number = 1): void { + if (ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR') { + return; + } + this.logText(indentLevel, `[WARN] ${text}`); + } + + /** + * Uses for logging of the public methods of the pageobjects. + * @param text log text + * @param indentLevel log level + */ + static info(text: string, indentLevel: number = 3): void { + if (ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR' || + ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'WARN') { + return; + } + this.logText(indentLevel, `• ${text}`); + } + + /** + * Uses for logging of the public methods of the pageobjects. + * @param text log text + * @param indentLevel log level + */ + static debug(text: string, indentLevel: number = 5): void { + if (ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR' || + ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'WARN' || + ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'INFO') { + return; + } + this.logText(indentLevel, `▼ ${text}`); + } + + /** + * Uses for logging of the public methods of the {@link DriverHelper} or + * private methods inside of pageobjects. + * @param text log text + * @param indentLevel log level + */ + static trace(text: string, indentLevel: number = 6): void { + if (ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'ERROR' || + ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'WARN' || + ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'INFO' || + ReporterConstants.TS_SELENIUM_LOG_LEVEL === 'DEBUG') { + return; + } + this.logText(indentLevel, `‣ ${text}`); + } +======= + /** + * uses for logging of recoverable errors and general warnings. + * @param text log text + * @param indentLevel log level + */ + static warn(text: string = '', indentLevel: number = 1): void { + if (REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'ERROR') { + return; + } + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '[WARN] '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.warn(message); + } + } + + /** + * uses for logging of the public methods of the pageobjects. + * @param text log text + * @param indentLevel log level + */ + static info(text: string = '', indentLevel: number = 3): void { + if (REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'ERROR' || REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'WARN') { + return; + } + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '• '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.info(message); + } + } + + /** + * uses for logging of the public methods of the pageobjects. + * @param text log text + * @param indentLevel log level + */ + static debug(text: string = '', indentLevel: number = 5): void { + if ( + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'ERROR' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'WARN' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'INFO' + ) { + return; + } + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '▼ '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.debug(message); + } + } + + /** + * uses for logging of the public methods of the {@link DriverHelper} or + * private methods inside of pageobjects. + * @param text log text + * @param indentLevel log level + */ + static trace(text: string = '', indentLevel: number = 6): void { + if ( + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'ERROR' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'WARN' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'INFO' || + REPORTER_CONSTANTS.TS_SELENIUM_LOG_LEVEL === 'DEBUG' + ) { + return; + } + const callerInfo: string = this.getCallerInfo(); + const logLevelSymbol: string = '‣ '; + const message: string = this.getFullMessage(callerInfo, text); + this.logText(indentLevel, logLevelSymbol, message); + if (this.sendLogMessageIntoReportPortal()) { + rpApi.trace(message); + } + } +>>>>>>> main + + private static getFullMessage(callerInfo: string, text: string): string { + return `${callerInfo}${this.separator(text, callerInfo)}${text}`; + } + + private static separator(text: string, caller: string): string { + return text ? (caller ? ' - ' : '') : ''; + } + + private static logText(messageIndentationLevel: number, logLevelSymbol: string, text: string): void { + if (text) { + // start group for every level + for (let i: number = 0; i < messageIndentationLevel; i++) { + console.group(); + } + // print the trimmed text + // if multiline, the message should be properly padded + console.log(logLevelSymbol + text); + // end group for every level + for (let i: number = 0; i < messageIndentationLevel; i++) { + console.groupEnd(); + } + } + } + + private static getCallerInfo(i: number = 4): string { + const stack: string[] = this.getCallStackArray(); + // " at functionName ( ..." => "functionName" + return stack[i].includes('. { + return acc || /MochaHooks|CheReporter/.test(e); + }, false); + } +} diff --git a/tests/e2e/utils/ScreenCatcher.ts b/tests/e2e/utils/ScreenCatcher.ts index 77f6530d77b..d416aef6ea0 100644 --- a/tests/e2e/utils/ScreenCatcher.ts +++ b/tests/e2e/utils/ScreenCatcher.ts @@ -1,5 +1,5 @@ -/********************************************************************* - * Copyright (c) 2021-2023 Red Hat, Inc. +/** ******************************************************************* + * copyright (c) 2021-2023 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,67 +8,78 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ import * as fs from 'fs'; -import { injectable, inject } from 'inversify'; +import { WriteStream } from 'fs'; +import { inject, injectable } from 'inversify'; import { CLASSES } from '../configs/inversify.types'; import { DriverHelper } from './DriverHelper'; import { error } from 'selenium-webdriver'; -import { WriteStream } from 'fs'; import { StringUtil } from './StringUtil'; -import { ReporterConstants } from '../constants/ReporterConstants'; +import { REPORTER_CONSTANTS } from '../constants/REPORTER_CONSTANTS'; @injectable() export class ScreenCatcher { - constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } - - async catchMethodScreen(methodName: string, methodIndex: number, screenshotIndex: number): Promise { - 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, ''); + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} - if (!fs.existsSync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER)) { - fs.mkdirSync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER); - } + 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(executionScreenCastDir)) { - fs.mkdirSync(executionScreenCastDir); - } + if (!fs.existsSync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER)) { + fs.mkdirSync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + } - const date: Date = new Date(); - const timeStr: string = date.toLocaleTimeString('en-us', { hour12: false }) + '.' + new Intl.NumberFormat('en-us', { minimumIntegerDigits: 3 }).format(date.getMilliseconds()); + if (!fs.existsSync(executionScreenCastDir)) { + fs.mkdirSync(executionScreenCastDir); + } - const screenshotPath: string = `${executionScreenCastDir}/${formattedMethodIndex}-${formattedScreenshotIndex}--(${StringUtil.sanitizeTitle(timeStr)})_${StringUtil.sanitizeTitle(methodName)}.png`; + const date: Date = new Date(); + const timeStr: string = + date.toLocaleTimeString('en-us', { hour12: false }) + + '.' + + new Intl.NumberFormat('en-us', { minimumIntegerDigits: 3 }).format(date.getMilliseconds()); - try { - await this.catchScreen(screenshotPath); - } catch (err) { - if (!fs.existsSync(executionScreenCastErrorsDir)) { - fs.mkdirSync(executionScreenCastErrorsDir); - } + const screenshotPath: string = `${executionScreenCastDir}/${formattedMethodIndex}-${formattedScreenshotIndex}--(${StringUtil.sanitizeTitle( + timeStr + )})_${StringUtil.sanitizeTitle(methodName)}.png`; - let errorLogFilePath: string = screenshotPath.replace('.png', '.txt'); - errorLogFilePath = errorLogFilePath.replace(executionScreenCastDir, executionScreenCastErrorsDir); - if (err instanceof error.IError) { - await this.writeErrorLog(errorLogFilePath, err); - } - } - } + try { + await this.catchScreen(screenshotPath); + } catch (err) { + if (!fs.existsSync(executionScreenCastErrorsDir)) { + fs.mkdirSync(executionScreenCastErrorsDir); + } - 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(); - } + let errorLogFilePath: string = screenshotPath.replace('.png', '.txt'); + errorLogFilePath = errorLogFilePath.replace(executionScreenCastDir, executionScreenCastErrorsDir); + if (err instanceof error.IError) { + this.writeErrorLog(errorLogFilePath, err); + } + } + } - async writeErrorLog(errorLogPath: string, err: error.IError): Promise { - console.log(`Failed to save screenshot, additional information in the ${errorLogPath}`); + 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(); + } - 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/ScreenCatcher.ts.orig b/tests/e2e/utils/ScreenCatcher.ts.orig new file mode 100644 index 00000000000..217b357278c --- /dev/null +++ b/tests/e2e/utils/ScreenCatcher.ts.orig @@ -0,0 +1,103 @@ +/** ******************************************************************* + * copyright (c) 2021-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import * as fs from 'fs'; +import { WriteStream } from 'fs'; +import { inject, injectable } from 'inversify'; +import { CLASSES } from '../configs/inversify.types'; +import { DriverHelper } from './DriverHelper'; +import { error } from 'selenium-webdriver'; +<<<<<<< HEAD +import { WriteStream } from 'fs'; +import { StringUtil } from './StringUtil'; +import { ReporterConstants } from '../constants/ReporterConstants'; +======= +import { StringUtil } from './StringUtil'; +import { REPORTER_CONSTANTS } from '../constants/REPORTER_CONSTANTS'; +>>>>>>> main + +@injectable() +export class ScreenCatcher { + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + +<<<<<<< HEAD + async catchMethodScreen(methodName: string, methodIndex: number, screenshotIndex: number): Promise { + 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, ''); + + if (!fs.existsSync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER)) { + fs.mkdirSync(ReporterConstants.TS_SELENIUM_REPORT_FOLDER); + } +======= + 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(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER)) { + fs.mkdirSync(REPORTER_CONSTANTS.TS_SELENIUM_REPORT_FOLDER); + } +>>>>>>> main + + 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 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); + } + + 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(); + } + + 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 ff6613b531a..dbb11855565 100644 --- a/tests/e2e/utils/ShellExecutor.ts +++ b/tests/e2e/utils/ShellExecutor.ts @@ -1,17 +1,37 @@ -import { echo, exec, ShellString } from 'shelljs'; +/** ******************************************************************* + * 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 { exec, ShellString } from 'shelljs'; +import { Logger } from './Logger'; +import { injectable } from 'inversify'; +import { assert } from 'chai'; +@injectable() export class ShellExecutor { + wait(seconds: number): void { + this.executeCommand(`sleep ${seconds}s`); + } - static wait(seconds: number): void { - this.execWithLog(`sleep ${seconds}s`); - } + curl(link: string): ShellString { + return this.executeCommand(`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); - } + executeCommand(command: string): ShellString { + Logger.debug(command); + return exec(command); + } + executeArbitraryShellScript(command: string): string { + Logger.debug(command); + const output: ShellString = this.executeCommand(command); + if (output.stderr.length > 0) { + assert.fail(output.stderr); + } + return output.stdout; + } } diff --git a/tests/e2e/utils/StringUtil.ts b/tests/e2e/utils/StringUtil.ts index 7f2723b4227..28f76d47591 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 @@ -8,40 +8,83 @@ * SPDX-License-Identifier: EPL-2.0 **********************************************************************/ -import { injectable } from 'inversify'; import { Logger } from './Logger'; -import { KubernetesCommandLineToolsExecutor } from './KubernetesCommandLineToolsExecutor'; +import { injectable } from 'inversify'; @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(`${this.constructor.name}.${this.getProjectNameFromGitUrl.name} - ${url}`); - 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(`${this.constructor.name}.${this.getProjectNameFromGitUrl.name} - ${projectName}`); - return projectName; - } - - 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 - */ - - static updateCommandEnvsToShStyle(command: string): string { - return command.replace(/[{}]/g, '').replace(/(? !['git', ''].includes(e)) + .reverse()[0]; + Logger.debug(`${projectName}`); + return projectName; + } + + static sanitizeTitle(arg: string): string { + Logger.trace(); + + 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 + */ + + static updateCommandEnvsToShStyle(command: string): string { + Logger.trace(); + + 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(`RequestHandler request:\n` + request_censored); - } catch (err) { - Logger.error(`RequestHandler 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(`CheApiRequestHandler.enableResponseRedirects`); - 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(`RequestHandler response:\n` + response_censored); - } catch (err) { - Logger.error(`RequestHandler 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/CheApiRequestHandler.ts.orig b/tests/e2e/utils/request-handlers/CheApiRequestHandler.ts.orig new file mode 100644 index 00000000000..c488eb09d19 --- /dev/null +++ b/tests/e2e/utils/request-handlers/CheApiRequestHandler.ts.orig @@ -0,0 +1,137 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +<<<<<<< HEAD +import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'; +======= +import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; +>>>>>>> main +import { TYPES } from '../../configs/inversify.types'; +import { inject, injectable } from 'inversify'; +import { IAuthorizationHeaderHandler } from './headers/IAuthorizationHeaderHandler'; +import { Logger } from '../Logger'; +<<<<<<< HEAD +import { BaseTestConstants } from '../../constants/BaseTestConstants'; +======= +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +>>>>>>> main + +@injectable() +export class CheApiRequestHandler { + constructor( + @inject(TYPES.IAuthorizationHeaderHandler) + private readonly headerHandler: IAuthorizationHeaderHandler + ) {} + + /** + * 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: 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; + }); + } + + 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 delete(relativeUrl: string): Promise { + return await axios.delete(this.assembleUrl(relativeUrl), await this.headerHandler.get()); + } + +<<<<<<< HEAD + 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()); + } +>>>>>>> main + + 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 f52e71307a9..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/CheMultiuserAuthorizationHeaderHandler.ts.orig b/tests/e2e/utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler.ts.orig new file mode 100644 index 00000000000..15983c0b1a4 --- /dev/null +++ b/tests/e2e/utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler.ts.orig @@ -0,0 +1,81 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { AxiosRequestConfig } from 'axios'; +import { IAuthorizationHeaderHandler } from './IAuthorizationHeaderHandler'; +import { inject, injectable } from 'inversify'; +import { DriverHelper } from '../../DriverHelper'; +import { CLASSES } from '../../../configs/inversify.types'; +import { Logger } from '../../Logger'; +import { IWebDriverCookie } from 'selenium-webdriver'; +<<<<<<< HEAD +import { BaseTestConstants, Platform } from '../../../constants/BaseTestConstants'; + +@injectable() +export class CheMultiuserAuthorizationHeaderHandler implements IAuthorizationHeaderHandler { + private authorizationToken: string = ''; + private readonly cookiesType: string = BaseTestConstants.TS_PLATFORM === Platform.OPENSHIFT ? '_oauth_proxy' : '_oauth2_proxy'; +======= +import { BASE_TEST_CONSTANTS, Platform } from '../../../constants/BASE_TEST_CONSTANTS'; + +@injectable() +export class CheMultiuserAuthorizationHeaderHandler implements IAuthorizationHeaderHandler { + private authorizationToken: string = ''; + private readonly cookiesType: string = BASE_TEST_CONSTANTS.TS_PLATFORM === Platform.OPENSHIFT ? '_oauth_proxy' : '_oauth2_proxy'; +>>>>>>> main + + constructor( + @inject(CLASSES.DriverHelper) + private readonly driverHelper: DriverHelper + ) {} + +<<<<<<< HEAD + 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!`); + } + } + + return { headers: { 'cookie': `${this.cookiesType}=${this.authorizationToken}` } }; + } +======= + 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}` + } + }; + } +>>>>>>> main +} diff --git a/tests/e2e/utils/request-handlers/headers/IAuthorizationHeaderHandler.ts b/tests/e2e/utils/request-handlers/headers/IAuthorizationHeaderHandler.ts index 6f81e5a48c1..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 a0209ed4645..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(`ApiUrlResolver.obtainUserNamespace ${this.userNamespace}`); - if (this.userNamespace.length === 0) { - Logger.trace(`ApiUrlResolver.obtainUserNamespace 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(`ApiUrlResolver.obtainUserNamespace 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 29d6f923664..1fd3ce0ae56 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(workspaceName: string, expectedWorkspaceStatus: WorkspaceStatus): Promise; + + stopWorkspaceByName(workspaceName: string): Promise; + + /** + * delete a workspace without stopping phase (similar with force deleting) + */ + deleteWorkspaceByName(workspaceName: string): Promise; + + /** + * stop workspace before deleting with checking stopping phase + */ + stopAndDeleteWorkspaceByName(workspaceName: string): Promise; + + /** + * stop all run workspaces in the namespace + */ + stopAllRunningWorkspaces(): Promise; + + /** + * stop all run workspaces, check statused and remove the workspaces + */ + stopAndDeleteAllRunningWorkspaces(): Promise; + + /** + * stop all run workspaces without stopping and waiting for of 'Stopped' phase + * Similar with 'force' deleting + */ + deleteAllWorkspaces(): Promise; } diff --git a/tests/e2e/utils/workspace/TestWorkspaceUtil.ts b/tests/e2e/utils/workspace/TestWorkspaceUtil.ts index c0f7263c750..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 @@ -9,7 +9,7 @@ **********************************************************************/ import 'reflect-metadata'; -import { injectable, inject } from 'inversify'; +import { inject, injectable } from 'inversify'; import { DriverHelper } from '../DriverHelper'; import { WorkspaceStatus } from './WorkspaceStatus'; import { error } from 'selenium-webdriver'; @@ -19,146 +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('TestWorkspaceUtil.waitWorkspaceStatus'); - - 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(`TestWorkspaceUtil.stopWorkspaceByName: ${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(`TestWorkspaceUtil.stopWorkspaceByName: ${workspaceName} stopped successfully`); - } - - // delete a workspace without stopping phase (similar with force deleting) - async deleteWorkspaceByName(workspaceName: string): Promise { - Logger.debug(`TestWorkspaceUtil.deleteWorkspaceByName: ${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(`TestWorkspaceUtil.stopWorkspaceByName: ${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('TestWorkspaceUtil.stopAndDeleteWorkspaceByName'); - - await this.stopWorkspaceByName(workspaceName); - await this.deleteWorkspaceByName(workspaceName); - } - - // stop all run workspaces in the namespace - async stopAllRunningWorkspaces(namespace: string): Promise { - Logger.debug('TestWorkspaceUtil.stopAllRunProjects'); - 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('TestWorkspaceUtil.stopAndDeleteAllRunProjects'); - 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('TestWorkspaceUtil.deleteAllRunProjects'); - 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/TestWorkspaceUtil.ts.orig b/tests/e2e/utils/workspace/TestWorkspaceUtil.ts.orig new file mode 100644 index 00000000000..f8b0caed183 --- /dev/null +++ b/tests/e2e/utils/workspace/TestWorkspaceUtil.ts.orig @@ -0,0 +1,232 @@ +/** ******************************************************************* + * copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import 'reflect-metadata'; +<<<<<<< HEAD +import { injectable, inject } from 'inversify'; +======= +import { inject, injectable } from 'inversify'; +>>>>>>> main +import { DriverHelper } from '../DriverHelper'; +import { WorkspaceStatus } from './WorkspaceStatus'; +import { error } from 'selenium-webdriver'; +import { CheApiRequestHandler } from '../request-handlers/CheApiRequestHandler'; +import { CLASSES } from '../../configs/inversify.types'; +import { Logger } from '../Logger'; +import axios, { AxiosResponse } from 'axios'; +import { ITestWorkspaceUtil } from './ITestWorkspaceUtil'; +import { ApiUrlResolver } from './ApiUrlResolver'; +<<<<<<< HEAD +import { TimeoutConstants } from '../../constants/TimeoutConstants'; + +@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; +======= +import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS'; + +@injectable() +export class TestWorkspaceUtil implements ITestWorkspaceUtil { + readonly polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING; + readonly attempts: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT / this.polling; +>>>>>>> main + + 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}`); + } + } + +<<<<<<< HEAD + async stopWorkspaceByName(workspaceName: string): Promise { + Logger.debug(`TestWorkspaceUtil.stopWorkspaceByName: ${workspaceName}`); +======= + async stopWorkspaceByName(workspaceName: string): Promise { + Logger.debug(`${workspaceName}`); +>>>>>>> main + + const stopWorkspaceApiUrl: string = await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName); + let stopWorkspaceResponse: AxiosResponse; + +<<<<<<< HEAD + 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; + } +======= + 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; + } +>>>>>>> main + + if (stopWorkspaceResponse.status !== 200) { + throw new Error(`Cannot stop workspace. Code: ${stopWorkspaceResponse.status} Data: ${stopWorkspaceResponse.data}`); + } + +<<<<<<< HEAD + await this.waitWorkspaceStatus(workspaceName, WorkspaceStatus.STOPPED); + Logger.debug(`TestWorkspaceUtil.stopWorkspaceByName: ${workspaceName} stopped successfully`); + } + + // delete a workspace without stopping phase (similar with force deleting) + async deleteWorkspaceByName(workspaceName: string): Promise { + Logger.debug(`TestWorkspaceUtil.deleteWorkspaceByName: ${workspaceName}` ); +======= + 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}`); +>>>>>>> main + + 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}`); + } + +<<<<<<< HEAD + 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(`TestWorkspaceUtil.stopWorkspaceByName: ${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.`); + } + } +======= + 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.`); + } + } +>>>>>>> main + + // 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 dfd361597e5..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' } diff --git a/tests/performance/api-tests/api-test-lombok.sh b/tests/performance/api-tests/api-test-lombok.sh index 1edb00176f2..c85b8f80c8d 100755 --- a/tests/performance/api-tests/api-test-lombok.sh +++ b/tests/performance/api-tests/api-test-lombok.sh @@ -4,7 +4,7 @@ set -e wget -O /tmp/api-utils.sh https://raw.githubusercontent.com/eclipse/che/main/tests/performance/api-tests/api-utils.sh source /tmp/api-utils.sh -export TEST_DEVFILE_PATH="devfile-registry/devfiles/java11-maven-lombok__lombok-project-sample/devworkspace-che-code-latest.yaml" +export TEST_DEVFILE_PATH="devfile-registry/devfiles/java-maven-lombok__lombok-project-sample/devworkspace-che-code-latest.yaml" export WORKSPACE_NAME="java-lombok" export projectName="lombok-project-sample" export expectedCommandOutput="BUILD SUCCESS" diff --git a/tests/performance/api-tests/api-test-quarkus.sh b/tests/performance/api-tests/api-test-quarkus.sh index 8c9dfdbf8e0..c6ce1c03fe2 100644 --- a/tests/performance/api-tests/api-test-quarkus.sh +++ b/tests/performance/api-tests/api-test-quarkus.sh @@ -4,7 +4,7 @@ set -e wget -O /tmp/api-utils.sh https://raw.githubusercontent.com/eclipse/che/main/tests/performance/api-tests/api-utils.sh source /tmp/api-utils.sh -export TEST_DEVFILE_PATH="devfile-registry/devfiles/java11-maven-quarkus__quarkus-quickstarts/devworkspace-che-code-latest.yaml" +export TEST_DEVFILE_PATH="devfile-registry/devfiles/java-maven-quarkus__quarkus-quickstarts/devworkspace-che-code-latest.yaml" export WORKSPACE_NAME="quarkus-quickstart" export projectName="quarkus-quickstarts/getting-started" export expectedCommandOutput="BUILD SUCCESS" diff --git a/tests/performance/load-tests/README.md b/tests/performance/load-tests/README.md new file mode 100644 index 00000000000..bc28e3476a1 --- /dev/null +++ b/tests/performance/load-tests/README.md @@ -0,0 +1,20 @@ +# Overview +This script tests the performance of an OpenShift environment by running multiple workspaces simultaneously. It evaluates the system under test by checking the average results across all pods and identifying any failures that occur during the testing process. + +## Prerequisites +To run these tests, you will need: +- The `kubectl` client installed +- An OpenShift cluster with running OpenShift DevSpaces +- A test user logged into the DevSpaces Dashboard (this ensures that user namespaces are created) + +## Running load tests +Follow these steps to run the load tests: +1. Log in to the OpenShift cluster with OpenShift DevSpaces or Eclipse Che deployed from the terminal. +2. Start the `load-test.sh` script from `test/e2e/performance/load-tests`. Set the number of workspaces to start using the `-c` parameter (e.g., `./load-test.sh -c 5`). Set the timeout for waiting for workspaces to start using the `-t` parameter in seconds (e.g., `./load-test.sh -t 240`). +3. This script uses the local `example.yaml` file to start the workspaces. +4. Alternatively, you can provide a link to the test devworkspace YAML file using the `-l` argument (e.g., `./load-test.sh -l https://raw.githubusercontent.com/eclipse/che/main/tests/performance/load-tests/samples/simple-with-editor-pvc.yaml`). +5. If you want to start workspaces in separate namespaces (one workspace per namespace), use the `-s` as flag option (e.g., `./load-test.sh -s `). +6. The script will provide the average time for workspace starting and the number of failed workspaces. + +## Results and logs +If a workspace fails to start, the logs will be saved in the `logs` directory. diff --git a/tests/performance/load-tests/load-test.sh b/tests/performance/load-tests/load-test.sh new file mode 100755 index 00000000000..838194879f4 --- /dev/null +++ b/tests/performance/load-tests/load-test.sh @@ -0,0 +1,259 @@ +#!/bin/bash + +set -e + +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Do cleanup if the script is interrupted or fails +trap cleanup ERR SIGINT +# Detect the operating system +OS="$(uname)" + +# Capture start time +start=$(date +%s) +# Current namespace where the script is running +current_namespace=$(kubectl config view --minify --output 'jsonpath={..namespace}') +start_separately=false +# Default value for test namespace name +test_namespace_name=load-test-namespace- +# Default value for test devworkspace name +dw_name=load-test-dw- +# default values for label selector +label_type="test-type" +label_key="load-test" + +function print() { + echo -e "${GREEN}$1${NC}" +} + +function print_error() { + echo -e "${RED}$1${NC}" +} + +# Function to display help information +function display_help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " -t Set the timeout in seconds (default: 120)" + echo " -c Set the number of workspaces to start (default: 3)" + echo " -l Set the link to the devworkspace.yaml file" + echo " -s Start workspaces in separate namespaces(one workspace per namespace)" + echo " --help Display this help message" + exit 0 +} + +function parseArguments() { + for arg in "$@"; do + case $arg in + # Check for --help argument + --help) + display_help + ;; + esac + done + + while getopts "t:c:l:sh" opt; do + case $opt in + t) + export WORKSPACE_IDLE_TIMEOUT=$OPTARG + ;; + c) # Check if the argument to -c is a number + if ! [[ $OPTARG =~ ^[0-9]+$ ]]; then + print_error "Error: Option -c requires a numeric argument." >&2 + exit 1 + fi + export COMPLETITIONS_COUNT=$OPTARG + ;; + l) + export DEVWORKSPACE_LINK=$OPTARG + ;; + s) + export start_separately=true + ;; + h) + display_help + ;; + \?) + print_error "Invalid option -c. Try for example something like ./load-test.sh -c 7" + exit 1 + ;; + esac + done +} + +function cleanup() { + echo "Clean up the environment" + + if [ $start_separately = true ]; then + echo "Delete test namespaces" + kubectl delete namespace --selector=$label_type=$label_key >/dev/null 2>&1 || true + else + kubectl delete dw --selector=$label_type=$label_key -n $current_namespace >/dev/null 2>&1 || true + fi +} + +function checkScriptVariables() { + # Set the number of workspaces to start + if [ -z $COMPLETITIONS_COUNT ]; then + echo "Parameter -c wasn't set, setting completitions count to 3." + export COMPLETITIONS_COUNT=3 + echo "Parameter -c was set to $COMPLETITIONS_COUNT ." + fi + + # Set the number of timeouts for waiting for workspaces to start + if [ -z $WORKSPACE_IDLE_TIMEOUT ]; then + echo "Parameter -t wasn't set, setting timeout to 120 second." + export WORKSPACE_IDLE_TIMEOUT=120 + else + echo "Parameter -t was set to $WORKSPACE_IDLE_TIMEOUT second." + fi + + # Get devworkspace yaml from link if it is set + # example - https://raw.githubusercontent.com/eclipse/che/main/tests/performance/load-tests/samples/simple-ephemeral.yaml + if [ -n "$DEVWORKSPACE_LINK" ]; then + if curl --fail --insecure "$DEVWORKSPACE_LINK" -o devworkspace.yaml; then + echo "Download succeeded, saved to devworkspace.yaml file." + + echo "Check the devworkspace.yaml file content correctness." + if ! kubectl apply -f devworkspace.yaml --dry-run=server; then + print_error "Devworkspace.yaml file is not correct." + exit 1 + fi + else + print_error "Download of $DEVWORKSPACE_LINK file failed" + exit 1 + fi + else + print "Local devworkspace.yaml file will be used." + cp -f samples/simple-ephemeral.yaml devworkspace.yaml + fi +} + +function getDwStartingTime() { + start_time=$(kubectl get dw $dw_name$1 -n $2 --template='{{range .status.conditions}}{{if eq .type "Started"}}{{.lastTransitionTime}}{{end}}{{end}}') + end_time=$(kubectl get dw $dw_name$1 -n $2 --template='{{range .status.conditions}}{{if eq .type "Ready"}}{{.lastTransitionTime}}{{end}}{{end}}') + start_timestamp=$(getTimestamp $start_time) + end_timestamp=$(getTimestamp $end_time) + dw_starting_time=$((end_timestamp - start_timestamp)) + + print "Devworkspace $dw_name$1 in $2 namespace starting time: $dw_starting_time seconds" + echo $dw_starting_time >>logs/sum.log + kubectl delete dw $dw_name$1 -n $2 >/dev/null 2>&1 +} + +function precreateNamespaces() { + if [ $start_separately = true ]; then + echo "Create test namespaces" + for ((i = 1; i <= $COMPLETITIONS_COUNT; i++)); do + namespace=$test_namespace_name$i + kubectl create namespace $namespace + oc label namespace $namespace $label_type=$label_key >/dev/null 2>&1 + done + fi +} + +function getTimestamp() { + if [ "$OS" = "Darwin" ]; then + date -j -f "%Y-%m-%dT%H:%M:%S" "$1" "+%s" + else + [ "$OS" = "Linux" ] + date -d $1 +%s + fi +} + +function runTest() { + # add label to devworkspace.yaml + cat devworkspace.yaml | awk -v key="$label_type" -v value=" $label_key" '/metadata:/{$0=$0"\n labels:\n "key":"value}1' >patched-dw.yaml + + # start COMPLETITIONS_COUNT workspaces in parallel + namespace=$current_namespace + for ((i = 1; i <= $COMPLETITIONS_COUNT; i++)); do + if [ $start_separately = true ]; then + namespace=$test_namespace_name$i + fi + awk '/name:/ && !modif { sub(/name: .*/, "name: '"$dw_name$i"'"); modif=1 } {print}' patched-dw.yaml | kubectl apply -n $namespace -f - & + done + wait + + # wait for all workspaces to be started + echo "Wait for all workspaces are started" + namespace=$current_namespace + for ((i = 1; i <= $COMPLETITIONS_COUNT; i++)); do + if [ $start_separately = true ]; then + namespace=$test_namespace_name$i + fi + kubectl wait --for=condition=Ready "dw/$dw_name$i" --timeout=${WORKSPACE_IDLE_TIMEOUT}s -n $namespace || true & + done + wait + + # Delete logs on file system if it exists + rm -f logs/* + # Create logs directory + mkdir logs || true + touch logs/sum.log + + # Get events from all cluster in start_separately mode and only from current namespace in default mode + if [ $start_separately = true ]; then + kubectl get events --field-selector involvedObject.kind=Pod --all-namespaces >logs/events.log + else + kubectl get events --field-selector involvedObject.kind=Pod >logs/events.log + fi + + total_time=0 + succeeded=0 + echo "Calculate average workspaces starting time" + namespace=$current_namespace + for ((i = 1; i <= $COMPLETITIONS_COUNT; i++)); do + if [ $start_separately = true ]; then + namespace=$test_namespace_name$i + fi + + if ! kubectl get dw $dw_name$i -n $namespace &>/dev/null; then + echo "$dw_name$i devworkspace does not exist. Moving to the next iteration." + continue + fi + + if [ "$(kubectl get dw $dw_name$i -n $namespace --template='{{.status.phase}}')" == "Running" ]; then + getDwStartingTime $i $namespace & + succeeded=$((succeeded + 1)) + else + print_error "Timeout waiting for $dw_name$i to become ready or an error occurred." + devworkspace_id=$(kubectl get dw $dw_name$i -n $namespace --template='{{.status.devworkspaceId}}') + kubectl describe dw $dw_name$i -n $namespace >logs/$dw_name$i-describe.log + cat logs/events.log | grep $devworkspace_id >logs/$dw_name$i-$devworkspace_id-events.log || true + fi + done + + wait +} + +function printResults() { + # Calculate average workspace starting time + while IFS= read -r line; do + ((total_time += line)) + done <"logs/sum.log" + + echo "==================== Test results ====================" + if [ $succeeded -eq 0 ]; then + print_error "No workspaces started successfully." + else + print "Average workspace starting time for $succeeded workspaces from $COMPLETITIONS_COUNT started: $((total_time / succeeded)) seconds" + fi + print "$((COMPLETITIONS_COUNT - succeeded)) workspaces failed. See failed workspace pod logs in the current folder for details." + + # Calculate and display the elapsed time + end=$(date +%s) + print "Elapsed time: $((end - start)) seconds" +} + +parseArguments "$@" +checkScriptVariables "$@" +cleanup + +precreateNamespaces +runTest +printResults + +cleanup diff --git a/tests/performance/load-tests/samples/simple-ephemeral.yaml b/tests/performance/load-tests/samples/simple-ephemeral.yaml new file mode 100644 index 00000000000..301a93ba360 --- /dev/null +++ b/tests/performance/load-tests/samples/simple-ephemeral.yaml @@ -0,0 +1,13 @@ +kind: DevWorkspace +apiVersion: workspace.devfile.io/v1alpha2 +metadata: + name: code-latest +spec: + started: true + template: + attributes: + controller.devfile.io/storage-type: ephemeral + components: + - name: dev + container: + image: quay.io/devfile/universal-developer-image:latest diff --git a/tests/performance/load-tests/samples/simple-pvc.yaml b/tests/performance/load-tests/samples/simple-pvc.yaml new file mode 100644 index 00000000000..0c89ca4bdcd --- /dev/null +++ b/tests/performance/load-tests/samples/simple-pvc.yaml @@ -0,0 +1,11 @@ +kind: DevWorkspace +apiVersion: workspace.devfile.io/v1alpha2 +metadata: + name: code-latest +spec: + started: true + template: + components: + - name: dev + container: + image: quay.io/devfile/universal-developer-image:latest diff --git a/tests/performance/load-tests/samples/simple-with-editor-ephemeral.yaml b/tests/performance/load-tests/samples/simple-with-editor-ephemeral.yaml new file mode 100644 index 00000000000..3efa0962aa4 --- /dev/null +++ b/tests/performance/load-tests/samples/simple-with-editor-ephemeral.yaml @@ -0,0 +1,22 @@ +kind: DevWorkspace +apiVersion: workspace.devfile.io/v1alpha2 +metadata: + name: code-latest +spec: + started: true + template: + attributes: + controller.devfile.io/storage-type: ephemeral + components: + - name: dev + container: + image: quay.io/devfile/universal-developer-image:latest + contributions: + - name: che-code + uri: https://eclipse-che.github.io/che-plugin-registry/main/v3/plugins/che-incubator/che-code/latest/devfile.yaml + components: + - name: che-code-runtime-description + container: + env: + - name: CODE_HOST + value: 0.0.0.0 diff --git a/tests/performance/load-tests/samples/simple-with-editor-pvc.yaml b/tests/performance/load-tests/samples/simple-with-editor-pvc.yaml new file mode 100644 index 00000000000..f0d42bc66bd --- /dev/null +++ b/tests/performance/load-tests/samples/simple-with-editor-pvc.yaml @@ -0,0 +1,20 @@ +kind: DevWorkspace +apiVersion: workspace.devfile.io/v1alpha2 +metadata: + name: code-latest +spec: + started: true + template: + components: + - name: dev + container: + image: quay.io/devfile/universal-developer-image:latest + contributions: + - name: che-code + uri: https://eclipse-che.github.io/che-plugin-registry/main/v3/plugins/che-incubator/che-code/latest/devfile.yaml + components: + - name: che-code-runtime-description + container: + env: + - name: CODE_HOST + value: 0.0.0.0