diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 662d3fe..c54c231 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -2,7 +2,7 @@ name: Bug report description: Create a report to help us improve title: "[BUG]: " labels: [ bug ] -assignees: ElenaStepuro +assignees: Alex-Reif body: - type: textarea @@ -73,4 +73,4 @@ body: attributes: label: Additional context description: Add any other context about the problem here - placeholder: For example, screenshot or using of additional frameworks like Sizzle library, Robot Framework or JDI, etc. If you can please, send a link to your project. \ No newline at end of file + placeholder: For example, screenshot or using of additional frameworks like Sizzle library, Robot Framework or JDI, etc. If you can please, send a link to your project. diff --git a/.github/ISSUE_TEMPLATE/custom.yml b/.github/ISSUE_TEMPLATE/custom.yml index 68845c8..bdf75c4 100644 --- a/.github/ISSUE_TEMPLATE/custom.yml +++ b/.github/ISSUE_TEMPLATE/custom.yml @@ -2,7 +2,7 @@ name: Help-support template description: Describe you problem happened using Healenium and team will help title: "[Need support]: " labels: [ help wanted ] -assignees: ElenaStepuro +assignees: Alex-Reif body: - type: markdown attributes: @@ -58,4 +58,4 @@ body: attributes: label: Additional context description: Add any other context about the problem here - placeholder: For example, screenshot or using of additional frameworks like Sizzle library, Robot Framework or JDI, etc. If you can please, send a link to your project. \ No newline at end of file + placeholder: For example, screenshot or using of additional frameworks like Sizzle library, Robot Framework or JDI, etc. If you can please, send a link to your project. diff --git a/README.md b/README.md index 2185156..e1b14f3 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,15 @@ Python 3.9.5 + Pytest project with healenium usage example [1. Start Healenium components](#1-start-healenium-components) -* [Healenium with Selenoid](#run-healenium-with-selenoid) * [Healenium with Selenium-Grid](#run-healenium-with-selenium-grid) +* [Healenium with Selenoid](#run-healenium-with-selenoid) + -[2. Run test](#2-run-test) +[2. Configuration RemoteWebDriver for Healenium](#2-configuration-remotewebdriver-for-healenium) -[3. Monitoring tests running](#3-monitoring-tests-running) +[3. Run test](#3-run-test) + +[4. Monitoring tests running](#4-monitoring-tests-running) ## How to start @@ -21,27 +24,28 @@ Go into healenium folder ```sh cd healenium -``` +``` + +#### Run Healenium with Selenium-Grid: +```sh +docker-compose up -d +``` -#### Run Healenium with Selenoid: +#### Run Healenium with Selenoid > Note: `browsers.json` consists of target browsers and appropriate versions. > Before run healenium you have to manually pull selenoid browser docker images with version specified in browsers.json Example pull selenoid chrome image: ```sh -docker pull selenoid/vnc:chrome_102.0 +docker pull selenoid/vnc:chrome_111.0 ``` Full list of browser images you can find [here](https://hub.docker.com/u/selenoid) -Run healenium with Selenoid: -```sh -docker-compose up -d -``` -#### Run Healenium with Selenium-Grid: +Run healenium with Selenoid: ```sh -docker-compose -f docker-compose-selenium-grid.yaml up -d +docker-compose -f docker-compose-selenoid.yaml up -d ``` ATTENTION @@ -49,11 +53,28 @@ docker-compose -f docker-compose-selenium-grid.yaml up -d Verify the next images are Up and Running - `postgres-db` (PostgreSQL database to store etalon selector / healing / report) - `hlm-proxy` (Proxy client request to Selenium server) -- `hlm-bacand` (CRUD service) +- `hlm-backend` (CRUD service) - `selector imitator` (Convert healed locator to convenient format) - `selenoid`/`selenium-grid` (Selenium server) -### 2. Run test +### 2. Configuration RemoteWebDriver for Healenium + +To run using Healenium create RemoteWebDriver with URL ```http://:8085```: + +```py + options = webdriver.ChromeOptions() + self.driver = webdriver.Remote('http://localhost:8085', options=options) +``` + +To temporarily disable the healing mechanism for certain sections of your code, use the following syntax: + +```py + self.driver.execute_script("disable_healing_true") + ... // Your code that does not require healing + self.driver.execute_script("disable_healing_false") +``` + +### 3. Run test To run tests in terminal with pytest you need to go to execute next commands: ```sh @@ -73,13 +94,13 @@ python -m pip install -U selenium ``` ```sh -python -m pytest ./tests/ +pytest ``` > If you want to execute tests from specified file, please use the command: ```python -m pytest ./tests/test_css.py``` >> In case you want to run all tests in project use ```python -m pytest ./tests/``` command -### 3. Monitoring tests running +### 4. Monitoring tests running You can monitor tests running if you using Healenium with Selenoid plus Selenoid Ui, go to:
```sh http://localhost:8080 diff --git a/healenium/LICENSE b/healenium/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/healenium/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/healenium/README.md b/healenium/README.md index e6f8235..bce8fee 100644 --- a/healenium/README.md +++ b/healenium/README.md @@ -2,14 +2,18 @@ [![Docker Pulls](https://img.shields.io/docker/pulls/healenium/hlm-backend.svg?maxAge=25920)](https://hub.docker.com/u/healenium) [![License](https://img.shields.io/badge/license-Apache-brightgreen.svg)](https://www.apache.org/licenses/LICENSE-2.0) +[![@healenium](https://img.shields.io/badge/Telegram-%40healenium-orange.svg)](https://t.me/healenium) ### Table of Contents [Overall information](#overall-information) [Healenium installation](#healenium-installation) -* [Healenium with Selenoid](#run-healenium-with-selenoid) * [Healenium with Selenium-Grid](#run-healenium-with-selenium-grid) +* [Healenium with Selenoid](#run-healenium-with-selenoid) +* [Healenium with Appium](#run-healenium-with-appium-only) + +[Healenium installation without Docker](#healenium-installation-without-docker) [Language Examples](#language-examples) * [Java](#java) @@ -24,10 +28,13 @@ Healenium acts as proxy between client and selenium server. `Docker-compose` includes the following services: - `postgres-db` (PostgreSQL database to store etalon selector / healing / report) - `hlm-proxy` (Proxy client request to Selenium server) -- `hlm-bacand` (CRUD service) +- `hlm-backend` (CRUD service) - `selector imitator` (Convert healed locator to convenient format) - `selenoid`/`selenium-grid` (Selenium server) +image + + ### Healenium installation Clone Healenium repository: @@ -35,6 +42,11 @@ Clone Healenium repository: git clone https://github.com/healenium/healenium.git ``` +#### Run Healenium with Selenium-Grid: +```sh +docker-compose up -d +``` + #### Run Healenium with Selenoid > Note: `browsers.json` consists of target browsers and appropriate versions. @@ -42,19 +54,54 @@ git clone https://github.com/healenium/healenium.git Example pull selenoid chrome image: ```sh -docker pull selenoid/vnc:chrome_102.0 +docker pull selenoid/vnc:chrome_111.0 ``` Full list of browser images you can find [here](https://hub.docker.com/u/selenoid) + Run healenium with Selenoid: ```sh -docker-compose up -d +docker-compose -f docker-compose-selenoid.yaml up -d ``` -#### Run Healenium with Selenium-Grid: +#### Run Healenium with Appium only + ```sh -docker-compose -f docker-compose-selenium-grid.yaml up -d +docker-compose -f docker-compose-appium.yaml up -d ``` +More details about integration Healenium with Appium [here](https://github.com/healenium/healenium-appium) + + +### Healenium installation without Docker + +Go to shell-installation: + +```sh +cd shell-installatio +``` + +There are web and remote options to run healenium. + +1. Start PostgeSql server. +- Create user (healenium_user/YDk2nmNs4s9aCP6K) (example data) +- Set attribute 'Can Login' (true) to user +- Create database (healenium) and set owner healenium_user +- Create schema (healenium) and set owner healenium_user + +2. Specify your db user and password data in the bash script 'start_healenium.sh'. + +3. Setup selenium server (selenium-grid) + +Download healenium services +```sh +download_services.sh +``` + +Run shell command to launch healenium components +```sh +start_healenium.sh +``` + ### Language examples diff --git a/healenium/docker-compose-appium.yaml b/healenium/docker-compose-appium.yaml new file mode 100644 index 0000000..d1472db --- /dev/null +++ b/healenium/docker-compose-appium.yaml @@ -0,0 +1,75 @@ +version: "3.8" + +services: + + postgres-db: + image: postgres:15.5-alpine + container_name: postgres-db + restart: always + ports: + - "5432:5432" + volumes: + - ./db/sql/init.sql:/docker-entrypoint-initdb.d/init.sql + environment: + - POSTGRES_DB=healenium + - POSTGRES_USER=healenium_user + - POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K + networks: + - healenium + + healenium: + image: healenium/hlm-backend:3.4.6 + container_name: healenium + restart: on-failure + ports: + - "7878:7878" + links: + - postgres-db + environment: + - SPRING_POSTGRES_DB=healenium + - SPRING_POSTGRES_SCHEMA=healenium + - SPRING_POSTGRES_USER=healenium_user + - SPRING_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K + - SPRING_POSTGRES_DB_HOST=postgres-db + - KEY_SELECTOR_URL=false + - COLLECT_METRICS=true + - FIND_ELEMENTS_AUTO_HEALING=false + - HLM_LOG_LEVEL=info + volumes: + - ./screenshots/:/screenshots + - ./logs/:/logs + networks: + - healenium + + selector-imitator: + image: healenium/hlm-selector-imitator:1.4 + container_name: selector-imitator + restart: on-failure + ports: + - "8000:8000" + networks: + - healenium + + hlm-proxy: + image: healenium/hlm-proxy:2.1.1 + container_name: hlm-proxy + restart: on-failure + ports: + - "8085:8085" + environment: + - RECOVERY_TRIES=1 + - SCORE_CAP=.6 + - HEAL_ENABLED=true + - SELENIUM_SERVER_URL=http://host.docker.internal:4723/wd/hub + - HEALENIUM_SERVER_URL=http://localhost:7878 + - HEALENIUM_SERVICE=http://healenium:7878 + - IMITATE_SERVICE=http://selector-imitator:8000 + - HLM_LOG_LEVEL=info + volumes: + - ./logs/:/logs + networks: + - healenium + +networks: + healenium: + name: healenium diff --git a/healenium/docker-compose-selenium-grid.yaml b/healenium/docker-compose-selenium-grid.yaml deleted file mode 100644 index c95fc57..0000000 --- a/healenium/docker-compose-selenium-grid.yaml +++ /dev/null @@ -1,114 +0,0 @@ -version: "3.9" - -services: - - postgres-db: - image: postgres:11-alpine - container_name: postgres-db - restart: always - ports: - - "5432:5432" - volumes: - - ./db/sql/init.sql:/docker-entrypoint-initdb.d/init.sql - environment: - - POSTGRES_DB=healenium - - POSTGRES_USER=healenium_user - - POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K - networks: - - healenium - - healenium: - image: healenium/hlm-backend:3.2.3 - container_name: healenium - restart: on-failure - ports: - - "7878:7878" - links: - - postgres-db - environment: - - SPRING_POSTGRES_DB=healenium - - SPRING_POSTGRES_SCHEMA=healenium - - SPRING_POSTGRES_USER=healenium_user - - SPRING_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K - - SPRING_POSTGRES_DB_HOST=postgres-db - networks: - - healenium - - selector-imitator: - image: healenium/hlm-selector-imitator:1.1 - container_name: selector-imitator - restart: on-failure - ports: - - "8000:8000" - networks: - - healenium - - hlm-proxy: - image: healenium/hlm-proxy:1.0.0 - container_name: hlm-proxy - restart: on-failure - ports: - - "8085:8085" - environment: - - RECOVERY_TRIES=1 - - SCORE_CAP=.6 - - HEAL_ENABLED=true - - SELENIUM_HOST=selenium-hub - - HEALENIUM_HOST=healenium - - IMITATE_HOST=selector-imitator - - SELENIUM_URL=/ - networks: - - healenium - - chrome: - image: selenium/node-chrome:103.0 - container_name: node-chrome - shm_size: 2gb - depends_on: - - selenium-hub - environment: - - SE_EVENT_BUS_HOST=selenium-hub - - SE_EVENT_BUS_PUBLISH_PORT=4442 - - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 - networks: - - healenium - - edge: - image: selenium/node-edge:103.0 - container_name: node-edge - shm_size: 2gb - depends_on: - - selenium-hub - environment: - - SE_EVENT_BUS_HOST=selenium-hub - - SE_EVENT_BUS_PUBLISH_PORT=4442 - - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 - networks: - - healenium - - firefox: - image: selenium/node-firefox:101.0 - container_name: node-firefox - shm_size: 2gb - depends_on: - - selenium-hub - environment: - - SE_EVENT_BUS_HOST=selenium-hub - - SE_EVENT_BUS_PUBLISH_PORT=4442 - - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 - networks: - - healenium - - selenium-hub: - image: selenium/hub:4.3.0 - container_name: selenium-hub - ports: - - "4442:4442" - - "4443:4443" - - "4444:4444" - networks: - - healenium - -networks: - healenium: - name: healenium diff --git a/healenium/docker-compose-selenoid.yaml b/healenium/docker-compose-selenoid.yaml new file mode 100644 index 0000000..3cba688 --- /dev/null +++ b/healenium/docker-compose-selenoid.yaml @@ -0,0 +1,99 @@ +version: "3.8" + +services: + + postgres-db: + image: postgres:15.5-alpine + container_name: postgres-db + restart: always + ports: + - "5432:5432" + volumes: + - ./db/sql/init.sql:/docker-entrypoint-initdb.d/init.sql + environment: + - POSTGRES_DB=healenium + - POSTGRES_USER=healenium_user + - POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K + networks: + - healenium + + healenium: + image: healenium/hlm-backend:3.4.6 + container_name: healenium + restart: on-failure + ports: + - "7878:7878" + links: + - postgres-db + environment: + - SPRING_POSTGRES_DB=healenium + - SPRING_POSTGRES_SCHEMA=healenium + - SPRING_POSTGRES_USER=healenium_user + - SPRING_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K + - SPRING_POSTGRES_DB_HOST=postgres-db + - KEY_SELECTOR_URL=false + - COLLECT_METRICS=true + - FIND_ELEMENTS_AUTO_HEALING=false + - HLM_LOG_LEVEL=info + volumes: + - ./screenshots/:/screenshots + - ./logs/:/logs + networks: + - healenium + + selector-imitator: + image: healenium/hlm-selector-imitator:1.4 + container_name: selector-imitator + restart: on-failure + ports: + - "8000:8000" + networks: + - healenium + + hlm-proxy: + image: healenium/hlm-proxy:2.1.1 + container_name: hlm-proxy + restart: on-failure + ports: + - "8085:8085" + environment: + - RECOVERY_TRIES=1 + - SCORE_CAP=.6 + - HEAL_ENABLED=true + - SELENIUM_SERVER_URL=http://selenoid:4444/wd/hub + - HEALENIUM_SERVER_URL=http://localhost:7878 + - HEALENIUM_SERVICE=http://healenium:7878 + - IMITATE_SERVICE=http://selector-imitator:8000 + - HLM_LOG_LEVEL=info + volumes: + - ./logs/:/logs + networks: + - healenium + + selenoid: + image: aerokube/selenoid:latest-release + volumes: + - ./selenoid-config:/etc/selenoid + - /var/run/docker.sock:/var/run/docker.sock + - ./selenoid-config/video:/opt/selenoid/video + - ./selenoid-config/logs:/opt/selenoid/logs + environment: + - OVERRIDE_VIDEO_OUTPUT_DIR=/path/to/config/video + command: ["-conf", "/etc/selenoid/browsers.json", "-video-output-dir", "/opt/selenoid/video", "-log-output-dir", "/opt/selenoid/logs", "-container-network", "healenium"] + ports: + - "4444:4444" + networks: + - healenium + + selenoid-ui: + image: aerokube/selenoid-ui:latest-release + restart: on-failure + ports: + - "8080:8080" + command: [ "--selenoid-uri", "http://selenoid:4444" ] + networks: + - healenium + +networks: + healenium: + name: healenium diff --git a/healenium/docker-compose-web.yaml b/healenium/docker-compose-web.yaml new file mode 100644 index 0000000..12f9291 --- /dev/null +++ b/healenium/docker-compose-web.yaml @@ -0,0 +1,54 @@ +version: "3.8" + +services: + + postgres-db: + image: postgres:15.5-alpine + container_name: postgres-db + restart: always + ports: + - "5432:5432" + volumes: + - ./db/sql/init.sql:/docker-entrypoint-initdb.d/init.sql + environment: + - POSTGRES_DB=healenium + - POSTGRES_USER=healenium_user + - POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K + networks: + - healenium + + healenium: + image: healenium/hlm-backend:3.4.6 + container_name: healenium + restart: on-failure + ports: + - "7878:7878" + links: + - postgres-db + environment: + - SPRING_POSTGRES_DB=healenium + - SPRING_POSTGRES_SCHEMA=healenium + - SPRING_POSTGRES_USER=healenium_user + - SPRING_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K + - SPRING_POSTGRES_DB_HOST=postgres-db + - KEY_SELECTOR_URL=false + - COLLECT_METRICS=true + - HLM_LOG_LEVEL=info + volumes: + - ./screenshots/:/screenshots + - ./logs/:/logs + networks: + - healenium + + selector-imitator: + image: healenium/hlm-selector-imitator:1.4 + container_name: selector-imitator + restart: on-failure + ports: + - "8000:8000" + networks: + - healenium + +networks: + healenium: + name: healenium diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index 2dc30f0..2a8ff27 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -1,9 +1,9 @@ -version: "3.9" +version: "3.8" services: postgres-db: - image: postgres:11-alpine + image: postgres:15.5-alpine container_name: postgres-db restart: always ports: @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:${BACK_VERSION} + image: healenium/hlm-backend:3.4.6 container_name: healenium restart: on-failure ports: @@ -31,11 +31,18 @@ services: - SPRING_POSTGRES_USER=healenium_user - SPRING_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K - SPRING_POSTGRES_DB_HOST=postgres-db + - KEY_SELECTOR_URL=false + - COLLECT_METRICS=true + - FIND_ELEMENTS_AUTO_HEALING=false + - HLM_LOG_LEVEL=info + volumes: + - ./screenshots/:/screenshots + - ./logs/:/logs networks: - healenium selector-imitator: - image: healenium/hlm-selector-imitator:1.1 + image: healenium/hlm-selector-imitator:1.4 container_name: selector-imitator restart: on-failure ports: @@ -44,7 +51,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:${PROXY_VERSION} + image: healenium/hlm-proxy:2.1.1 container_name: hlm-proxy restart: on-failure ports: @@ -53,35 +60,65 @@ services: - RECOVERY_TRIES=1 - SCORE_CAP=.6 - HEAL_ENABLED=true - - SELENIUM_HOST=hlm-selenoid - - HEALENIUM_HOST=healenium - - IMITATE_HOST=selector-imitator - - SELENIUM_URL=/wd/hub + - SELENIUM_SERVER_URL=http://selenium-hub:4444/wd/hub + - HEALENIUM_SERVER_URL=http://localhost:7878 + - HEALENIUM_SERVICE=http://healenium:7878 + - IMITATE_SERVICE=http://selector-imitator:8000 + - HLM_LOG_LEVEL=info + volumes: + - ./logs/:/logs networks: - healenium - selenoid: - image: healenium/hlm-selenoid:0.1.0 - container_name: hlm-selenoid - restart: on-failure - ports: - - "4444:4444" + chrome: + image: selenium/node-chrome:latest + container_name: node-chrome + shm_size: 2gb + depends_on: + - selenium-hub environment: - - PROXY_CONTAINER_NAME=hlm-proxy - volumes: - - .:/etc/selenoid/:ro - - /var/run/docker.sock:/var/run/docker.sock - command: ["-container-network", "healenium"] + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + - SE_NODE_MAX_INSTANCES=5 + - SE_NODE_MAX_SESSIONS=5 + - SE_NODE_SESSION_TIMEOUT=20 networks: - healenium - selenoid-ui: - image: aerokube/selenoid-ui:1.10.5 - container_name: selenoid-ui - restart: on-failure + edge: + image: selenium/node-edge:latest + container_name: node-edge + shm_size: 2gb + depends_on: + - selenium-hub + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + networks: + - healenium + + firefox: + image: selenium/node-firefox:latest + container_name: node-firefox + shm_size: 2gb + depends_on: + - selenium-hub + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + networks: + - healenium + + selenium-hub: + image: selenium/hub:latest + container_name: selenium-hub ports: - - "8080:8080" - command: [ "--selenoid-uri", "http://hlm-selenoid:4444" ] + - "4442:4442" + - "4443:4443" + - "4444:4444" networks: - healenium diff --git a/healenium/browsers.json b/healenium/selenoid-config/browsers.json similarity index 50% rename from healenium/browsers.json rename to healenium/selenoid-config/browsers.json index 2029555..9807ec3 100644 --- a/healenium/browsers.json +++ b/healenium/selenoid-config/browsers.json @@ -1,27 +1,27 @@ { "chrome": { - "default": "102.0", + "default": "111.0", "versions": { - "102.0": { - "image": "selenoid/vnc:chrome_102.0", + "111.0": { + "image": "selenoid/vnc:chrome_111.0", "port": "4444" }, - "101.0": { - "image": "selenoid/vnc:chrome_101.0", + "110.0": { + "image": "selenoid/vnc:chrome_110.0", "port": "4444" } } }, "firefox": { - "default": "101.0", + "default": "111.0", "versions": { - "101.0": { - "image": "selenoid/vnc:firefox_101.0", + "111.0": { + "image": "selenoid/vnc:firefox_111.0", "port": "4444", "path": "/wd/hub" }, - "100.0": { - "image": "selenoid/vnc:firefox_100.0", + "110.0": { + "image": "selenoid/vnc:firefox_110.0", "port": "4444", "path": "/wd/hub" } diff --git a/healenium/shell-installation/selenium-grid/download_services.sh b/healenium/shell-installation/selenium-grid/download_services.sh new file mode 100644 index 0000000..90b33c1 --- /dev/null +++ b/healenium/shell-installation/selenium-grid/download_services.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Versions of the services +HLM_BACKEND_VERSION="3.4.6" +HLM_PROXY_VERSION="2.1.1" + +# Downloading +curl -L https://github.com/healenium/healenium-backend/releases/download/${HLM_BACKEND_VERSION}/healenium-backend-${HLM_BACKEND_VERSION}.jar > hlm-backend.jar + +curl -L https://github.com/healenium/healenium-proxy/releases/download/${HLM_PROXY_VERSION}/hlm-proxy-${HLM_PROXY_VERSION}.jar > hlm-proxy.jar + +git clone https://github.com/healenium/healenium-selector-imitator.git diff --git a/healenium/shell-installation/selenium-grid/start_healenium.sh b/healenium/shell-installation/selenium-grid/start_healenium.sh new file mode 100644 index 0000000..88fe583 --- /dev/null +++ b/healenium/shell-installation/selenium-grid/start_healenium.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Requirements hlm_backend +HLM_POSTGRES_DB=healenium +HLM_POSTGRES_SCHEMA=healenium +HLM_POSTGRES_USER=healenium_user +HLM_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K +HLM_COLLECT_METRICS=true +HLM_SERVER_PORT=7878 +HLM_LOG_LEVEL=info + +# Requirements hlm_proxy +RECOVERY_TRIES=1 +SCORE_CAP=.6 +HEAL_ENABLED=true +SELENIUM_SERVER_URL=http://localhost:4444 +HEALENIUM_SERVER_URL=http://localhost:7878 +HEALENIUM_SERVICE=http://localhost:7878 +IMITATE_SERVICE=http://localhost:8000 + +# Deploy the hlm-backend service +SPRING_POSTGRES_DB=$HLM_POSTGRES_DB SPRING_POSTGRES_SCHEMA=$HLM_POSTGRES_SCHEMA SPRING_POSTGRES_USER=$HLM_POSTGRES_USER SPRING_POSTGRES_PASSWORD=$HLM_POSTGRES_PASSWORD COLLECT_METRICS=$HLM_COLLECT_METRICS SPRING_SERVER_PORT=$HLM_SERVER_PORT HLM_LOG_LEVEL=$HLM_LOG_LEVEL java -jar hlm-backend.jar 2>&1 & echo $! > ./pid-hlm-backend.file & + +# Deploy the hlm-proxy service +RECOVERY_TRIES=$RECOVERY_TRIES SCORE_CAP=$SCORE_CAP HEAL_ENABLED=$HEAL_ENABLED SELENIUM_SERVER_URL=$SELENIUM_SERVER_URL HEALENIUM_SERVER_URL=$HEALENIUM_SERVER_URL HEALENIUM_SERVICE=$HEALENIUM_SERVICE IMITATE_SERVICE=$IMITATE_SERVICE HLM_LOG_LEVEL=$HLM_LOG_LEVEL java -jar hlm-proxy.jar 2>&1 & echo $! > ./pid-hlm-proxy.file & + +# Deploy the imitator service +pip install --upgrade pip + +pip install -r healenium-selector-imitator/requirements.txt + +if [[ $OSTYPE == 'msys'* ]]; +then + python healenium-selector-imitator/app.py & echo $! > ./pid-selector.file & +else + python3 healenium-selector-imitator/app.py & echo $! > ./pid-selector.file & +fi diff --git a/healenium/shell-installation/selenium-grid/stop_healenium.sh b/healenium/shell-installation/selenium-grid/stop_healenium.sh new file mode 100644 index 0000000..813ac0d --- /dev/null +++ b/healenium/shell-installation/selenium-grid/stop_healenium.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +kill $(cat ./pid-hlm-backend.file) $(cat ./pid-hlm-proxy.file) $(cat ./pid-selector.file) \ No newline at end of file diff --git a/healenium/shell-installation/web/download_services.sh b/healenium/shell-installation/web/download_services.sh new file mode 100644 index 0000000..a35c6be --- /dev/null +++ b/healenium/shell-installation/web/download_services.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Versions of the services +HLM_BACKEND_VERSION="3.4.6" + +# Downloading +curl -L https://github.com/healenium/healenium-backend/releases/download/${HLM_BACKEND_VERSION}/healenium-backend-${HLM_BACKEND_VERSION}.jar > hlm-backend.jar + +git clone https://github.com/healenium/healenium-selector-imitator.git diff --git a/healenium/shell-installation/web/start_healenium.sh b/healenium/shell-installation/web/start_healenium.sh new file mode 100644 index 0000000..d05a43e --- /dev/null +++ b/healenium/shell-installation/web/start_healenium.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Requirements hlm_backend +HLM_POSTGRES_DB=healenium +HLM_POSTGRES_SCHEMA=healenium +HLM_POSTGRES_USER=healenium_user +HLM_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K +HLM_COLLECT_METRICS=true +HLM_SERVER_PORT=7878 +HLM_LOG_LEVEL=info + +# Deploy the hlm-backend service +SPRING_POSTGRES_DB=$HLM_POSTGRES_DB SPRING_POSTGRES_SCHEMA=$HLM_POSTGRES_SCHEMA SPRING_POSTGRES_USER=$HLM_POSTGRES_USER SPRING_POSTGRES_PASSWORD=$HLM_POSTGRES_PASSWORD COLLECT_METRICS=$HLM_COLLECT_METRICS SPRING_SERVER_PORT=$HLM_SERVER_PORT HLM_LOG_LEVEL=$HLM_LOG_LEVEL java -jar hlm-backend.jar 2>&1 & echo $! > ./pid-hlm-backend.file & + +# Deploy the imitator service +pip install --upgrade pip + +pip install -r healenium-selector-imitator/requirements.txt + +if [[ $OSTYPE == 'msys'* ]]; +then + python healenium-selector-imitator/app.py & echo $! > ./pid-selector.file & +else + python3 healenium-selector-imitator/app.py & echo $! > ./pid-selector.file & +fi diff --git a/healenium/shell-installation/web/stop_healenium.sh b/healenium/shell-installation/web/stop_healenium.sh new file mode 100644 index 0000000..d71537d --- /dev/null +++ b/healenium/shell-installation/web/stop_healenium.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +kill $(cat ./pid-hlm-backend.file) $(cat ./pid-selector.file) \ No newline at end of file diff --git a/src/main/pages/base_page.py b/src/main/pages/base_page.py index eea3cba..ae20641 100644 --- a/src/main/pages/base_page.py +++ b/src/main/pages/base_page.py @@ -4,7 +4,7 @@ class BasePage(object): mainPageUrl = 'https://sha-test-app.herokuapp.com/' callbackTestPageUrl = 'https://mdn.github.io/web-components-examples/life-cycle-callbacks/' - testEnvPageUrl = 'https://elenastepuro.github.io/test_env/index.html' + testEnvPageUrl = 'https://healenium.github.io/healenium-test-env/index.html' def __init__(self, driver): self.driver = driver diff --git a/src/main/pages/callback_page.py b/src/main/pages/callback_page.py index b02a498..fc7bcb7 100644 --- a/src/main/pages/callback_page.py +++ b/src/main/pages/callback_page.py @@ -10,7 +10,7 @@ class CallbackPage(BasePage): remove_square_button = '//button[contains(@class, "remove")]' test_button = '//custom-square[contains(@c, "red")]' - test_button_css = '[c="red"]' + test_button_css = '[color="red"]' driver: webdriver @@ -20,7 +20,6 @@ def __init__(self): options.add_argument("--disable-dev-shm-usage") self.driver = webdriver.Remote( command_executor="http://localhost:8085", - desired_capabilities=webdriver.DesiredCapabilities.CHROME, options=options) def open_browser(self): diff --git a/src/main/pages/markup_page.py b/src/main/pages/markup_page.py index a58bc6e..f4c8a1c 100644 --- a/src/main/pages/markup_page.py +++ b/src/main/pages/markup_page.py @@ -29,12 +29,12 @@ def open_browser(self): return self def generate_markup(self): - generate_markup = self.driver.find_element(By.ID, self.generate_markup_btn_id) + generate_markup = self.driver.find_element_by_id(self.generate_markup_btn_id) generate_markup.click() return self def click_test_button(self): - self.driver.find_element(By.CLASS_NAME, self.test_button).click() + self.driver.find_element_by_class_name(self.test_button).click() def close(self): self.driver.quit() diff --git a/src/main/pages/testenv_page.py b/src/main/pages/testenv_page.py index a8deebc..65916b8 100644 --- a/src/main/pages/testenv_page.py +++ b/src/main/pages/testenv_page.py @@ -2,12 +2,15 @@ from selenium import webdriver from selenium.webdriver.common.by import By +from selenium.webdriver.support.wait import WebDriverWait from src.main.pages.base_page import BasePage from src.main.search.context import Context +from selenium.webdriver.support import expected_conditions as ec class TestEnvPage(BasePage): + __test__ = False submit_btn = 'Submit' submit_form_btn = 'Submit_checkbox' @@ -15,12 +18,7 @@ class TestEnvPage(BasePage): def __init__(self): options = webdriver.ChromeOptions() - options.add_argument('--no-sandbox') - options.add_argument("--disable-dev-shm-usage") - self.driver = webdriver.Remote( - command_executor="http://localhost:8085", - desired_capabilities=webdriver.DesiredCapabilities.CHROME, - options=options) + self.driver = webdriver.Remote('http://localhost:8085', options=options) def open_browser(self): self.driver.get(BasePage.testEnvPageUrl) @@ -33,11 +31,11 @@ def select_checkboxes(self): return self def click_form_submit_btn(self): - self.driver.find_element(By.ID, self.submit_form_btn).click() + self.driver.find_element_by_id(self.submit_form_btn).click() return self def click_submit_btn(self): - self.driver.find_element(By.ID, self.submit_btn).click() + self.driver.find_element_by_id(self.submit_btn).click() return self def select_checkboxes_under_parent(self): @@ -52,5 +50,14 @@ def find_test_element(self, locator_type, selector): result = Context().set_strategy(self.driver, locator_type).execute_strategy(selector) assert result == True + def click_wait_btn(self): + self.driver.find_element(By.ID, "Wait_Submit").click() + + def execute_script(self, script): + self.driver.execute_script(script) + + def click_test_button_wait(self): + WebDriverWait(self.driver, 10).until(ec.visibility_of_element_located((By.ID, "wait_new_element"))) + def close(self): self.driver.quit() diff --git a/tests/test_semantic.py b/tests/test_semantic.py index 418cb5b..cbad9d7 100644 --- a/tests/test_semantic.py +++ b/tests/test_semantic.py @@ -5,18 +5,18 @@ class TestSemantic: - def test_semantic_class_name(self): - main_page = MarkupPage() - - main_page.open_browser() - main_page.click_test_button() - main_page.confirm_alert() - - main_page.generate_markup() - main_page.click_test_button() # should be healed - main_page.confirm_alert() - - main_page.close() + # def test_semantic_class_name(self): + # main_page = MarkupPage() + # + # main_page.open_browser() + # main_page.click_test_button() + # main_page.confirm_alert() + # + # main_page.generate_markup() + # main_page.click_test_button() # should be healed + # main_page.confirm_alert() + # + # main_page.close() def test_semantic_id(self): test_page = TestEnvPage() diff --git a/tests/test_wait.py b/tests/test_wait.py index 1f4321d..9c7e021 100644 --- a/tests/test_wait.py +++ b/tests/test_wait.py @@ -1,21 +1,15 @@ -from src.main.pages.markup_page import MarkupPage +from src.main.pages.testenv_page import TestEnvPage class TestWait: def test_conditional_wait(self): - markup_page=MarkupPage() + test_page = TestEnvPage() - markup_page.open_browser() - markup_page.click_test_button() - markup_page.confirm_alert() + test_page.open_browser() + test_page.click_wait_btn() + test_page.execute_script("disable_healing_true") + test_page.click_test_button_wait() + test_page.execute_script("disable_healing_false") - markup_page.generate_markup() - markup_page.click_test_button() #should be healed - markup_page.confirm_alert() - - # markup_page.generate_markup() - # markup_page.click_test_button_wait(5) #should be healed - # markup_page.confirm_alert() - - markup_page.close() + test_page.close()