From d9e13be821fd60b2c9ffe1005edc09662a380b01 Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Thu, 4 Aug 2022 18:24:27 +0300 Subject: [PATCH 01/24] Revert "Change find element 4.3.0" This reverts commit bcad7eaa05cf05a202ba6ab48efa252303f1e31e. --- src/main/pages/markup_page.py | 4 ++-- src/main/pages/testenv_page.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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..0ec5f8a 100644 --- a/src/main/pages/testenv_page.py +++ b/src/main/pages/testenv_page.py @@ -33,11 +33,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): From 2439f607d91f701ecbc466924893e66ae88e0136 Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Thu, 4 Aug 2022 18:24:32 +0300 Subject: [PATCH 02/24] Revert "add .env file" This reverts commit fb2547094cac5c4ae7a8d1ecca0c56e8c56db904. --- healenium/docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index 2dc30f0..9f3d129 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:${BACK_VERSION} + image: healenium/hlm-backend:3.2.3 container_name: healenium restart: on-failure ports: @@ -44,7 +44,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:${PROXY_VERSION} + image: healenium/hlm-proxy:1.0.0 container_name: hlm-proxy restart: on-failure ports: From 7cb9290cce439727264f34863e3019ada93774da Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Fri, 5 Aug 2022 10:59:00 +0300 Subject: [PATCH 03/24] Update readme --- README.md | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2185156..4263aca 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,11 @@ Python 3.9.5 + Pytest project with healenium usage example * [Healenium with Selenoid](#run-healenium-with-selenoid) * [Healenium with Selenium-Grid](#run-healenium-with-selenium-grid) -[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 @@ -53,7 +55,24 @@ Verify the next images are Up and Running - `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 + nodeURL = "http://localhost:8085" + + options = webdriver.ChromeOptions() + options.add_argument('--no-sandbox') + + current_webdriver = webdriver.Remote( + command_executor=nodeURL, + desired_capabilities=webdriver.DesiredCapabilities.CHROME, + options=options, + ) +``` + +### 3. Run test To run tests in terminal with pytest you need to go to execute next commands: ```sh @@ -79,7 +98,7 @@ python -m pytest ./tests/ > 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 From dc8288cc348aba53e79556a75257abb0efd73431 Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Fri, 19 Aug 2022 13:47:02 +0300 Subject: [PATCH 04/24] Upgrade hlm-proxy to 1.1.0 --- README.md | 13 +++++-------- healenium/docker-compose-selenium-grid.yaml | 2 +- healenium/docker-compose.yaml | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 4263aca..96bfc0b 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ 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) @@ -60,16 +60,13 @@ Verify the next images are Up and Running To run using Healenium create RemoteWebDriver with URL ```http://:8085```: ```py - nodeURL = "http://localhost:8085" - options = webdriver.ChromeOptions() options.add_argument('--no-sandbox') - - current_webdriver = webdriver.Remote( - command_executor=nodeURL, + options.add_argument("--disable-dev-shm-usage") + self.driver = webdriver.Remote( + command_executor="http://localhost:8085", desired_capabilities=webdriver.DesiredCapabilities.CHROME, - options=options, - ) + options=options) ``` ### 3. Run test diff --git a/healenium/docker-compose-selenium-grid.yaml b/healenium/docker-compose-selenium-grid.yaml index c95fc57..d7c3519 100644 --- a/healenium/docker-compose-selenium-grid.yaml +++ b/healenium/docker-compose-selenium-grid.yaml @@ -44,7 +44,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.0.0 + image: healenium/hlm-proxy:1.1.0 container_name: hlm-proxy restart: on-failure ports: diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index 9f3d129..3a7a3a1 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -44,7 +44,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.0.0 + image: healenium/hlm-proxy:1.1.0 container_name: hlm-proxy restart: on-failure ports: From ab0ad1075406ad8df89eeb48833261993cfc5955 Mon Sep 17 00:00:00 2001 From: Aliaksei-Ashukha <69298932+Aliaksei-Ashukha@users.noreply.github.com> Date: Tue, 30 Aug 2022 16:08:27 +0300 Subject: [PATCH 05/24] Update docker-compose-selenium-grid.yaml --- healenium/docker-compose-selenium-grid.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/healenium/docker-compose-selenium-grid.yaml b/healenium/docker-compose-selenium-grid.yaml index d7c3519..79c29ae 100644 --- a/healenium/docker-compose-selenium-grid.yaml +++ b/healenium/docker-compose-selenium-grid.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.2.3 + image: healenium/hlm-backend:3.2.4 container_name: healenium restart: on-failure ports: @@ -31,6 +31,7 @@ services: - SPRING_POSTGRES_USER=healenium_user - SPRING_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K - SPRING_POSTGRES_DB_HOST=postgres-db + - KEY_SELECTOR_URL=true networks: - healenium From a19f1741c6349878a2ba0d2e7287fbf1ee3439c8 Mon Sep 17 00:00:00 2001 From: Aliaksei-Ashukha <69298932+Aliaksei-Ashukha@users.noreply.github.com> Date: Tue, 30 Aug 2022 16:08:59 +0300 Subject: [PATCH 06/24] Update docker-compose.yaml --- healenium/docker-compose.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index 3a7a3a1..63d2b7b 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.2.3 + image: healenium/hlm-backend:3.2.4 container_name: healenium restart: on-failure ports: @@ -31,6 +31,7 @@ services: - SPRING_POSTGRES_USER=healenium_user - SPRING_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K - SPRING_POSTGRES_DB_HOST=postgres-db + - KEY_SELECTOR_URL=true networks: - healenium From 6e3f942bbfca6ef037c0b84fd1db7f06ccddb62a Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Thu, 22 Dec 2022 14:28:42 +0300 Subject: [PATCH 07/24] Update docker-compose-selenium-grid.yaml --- healenium/docker-compose-selenium-grid.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/healenium/docker-compose-selenium-grid.yaml b/healenium/docker-compose-selenium-grid.yaml index 79c29ae..e1a0eda 100644 --- a/healenium/docker-compose-selenium-grid.yaml +++ b/healenium/docker-compose-selenium-grid.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.2.4 + image: healenium/hlm-backend:3.2.5 container_name: healenium restart: on-failure ports: @@ -45,7 +45,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.1.0 + image: healenium/hlm-proxy:1.2.1 container_name: hlm-proxy restart: on-failure ports: From 9d136b00a756d23b6e6f7d8bf8c520b5a67a17b9 Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Thu, 22 Dec 2022 14:29:04 +0300 Subject: [PATCH 08/24] Update docker-compose.yaml --- healenium/docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index 63d2b7b..3d9ecf3 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.2.4 + image: healenium/hlm-backend:3.2.5 container_name: healenium restart: on-failure ports: @@ -45,7 +45,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.1.0 + image: healenium/hlm-proxy:1.2.1 container_name: hlm-proxy restart: on-failure ports: From b9c4f6bdd7a4f5d95948c18a2a8e88b711149af8 Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Mon, 29 May 2023 02:07:49 +0300 Subject: [PATCH 09/24] Update docker-compose-selenium-grid.yaml --- healenium/docker-compose-selenium-grid.yaml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/healenium/docker-compose-selenium-grid.yaml b/healenium/docker-compose-selenium-grid.yaml index e1a0eda..a0645e7 100644 --- a/healenium/docker-compose-selenium-grid.yaml +++ b/healenium/docker-compose-selenium-grid.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.2.5 + image: healenium/hlm-backend:3.3.3 container_name: healenium restart: on-failure ports: @@ -31,12 +31,14 @@ services: - SPRING_POSTGRES_USER=healenium_user - SPRING_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K - SPRING_POSTGRES_DB_HOST=postgres-db - - KEY_SELECTOR_URL=true + - KEY_SELECTOR_URL=false + - COLLECT_METRICS=true + - HLM_LOG_LEVEL=info networks: - healenium selector-imitator: - image: healenium/hlm-selector-imitator:1.1 + image: healenium/hlm-selector-imitator:1.2 container_name: selector-imitator restart: on-failure ports: @@ -45,7 +47,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.2.1 + image: healenium/hlm-proxy:1.3.3 container_name: hlm-proxy restart: on-failure ports: @@ -54,10 +56,12 @@ services: - RECOVERY_TRIES=1 - SCORE_CAP=.6 - HEAL_ENABLED=true - - SELENIUM_HOST=selenium-hub - - HEALENIUM_HOST=healenium - - IMITATE_HOST=selector-imitator - - SELENIUM_URL=/ + - SELENIUM_SERVER_URL=http://hlm-selenoid:4444/wd/hub + - APPIUM_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 networks: - healenium From 06e68f9d81779064f4de0ee19151dcc29b4d837a Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Mon, 29 May 2023 02:09:08 +0300 Subject: [PATCH 10/24] Update docker-compose.yaml --- healenium/docker-compose.yaml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index 3d9ecf3..548bd46 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.2.5 + image: healenium/hlm-backend:3.3.3 container_name: healenium restart: on-failure ports: @@ -31,12 +31,14 @@ services: - SPRING_POSTGRES_USER=healenium_user - SPRING_POSTGRES_PASSWORD=YDk2nmNs4s9aCP6K - SPRING_POSTGRES_DB_HOST=postgres-db - - KEY_SELECTOR_URL=true + - KEY_SELECTOR_URL=false + - COLLECT_METRICS=true + - HLM_LOG_LEVEL=info networks: - healenium selector-imitator: - image: healenium/hlm-selector-imitator:1.1 + image: healenium/hlm-selector-imitator:1.2 container_name: selector-imitator restart: on-failure ports: @@ -45,7 +47,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.2.1 + image: healenium/hlm-proxy:1.3.3 container_name: hlm-proxy restart: on-failure ports: @@ -54,10 +56,12 @@ 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://hlm-selenoid:4444/wd/hub + - APPIUM_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 networks: - healenium From 508b6f97e1f2b7096e095fe092c58f45c2f9de7b Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Wed, 14 Jun 2023 00:37:02 +0300 Subject: [PATCH 11/24] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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. From 4a1b9273c824fe3bbb81179740f2f2463e259aa7 Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Wed, 14 Jun 2023 00:37:35 +0300 Subject: [PATCH 12/24] Update custom.yml --- .github/ISSUE_TEMPLATE/custom.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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. From 8a682de0b459ddb02b982535dc0fb01829ce3f35 Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Wed, 14 Jun 2023 13:41:33 +0300 Subject: [PATCH 13/24] Update docker-compose-selenium-grid.yaml --- healenium/docker-compose-selenium-grid.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/healenium/docker-compose-selenium-grid.yaml b/healenium/docker-compose-selenium-grid.yaml index a0645e7..033a0bf 100644 --- a/healenium/docker-compose-selenium-grid.yaml +++ b/healenium/docker-compose-selenium-grid.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.3.3 + image: healenium/hlm-backend:3.3.4 container_name: healenium restart: on-failure ports: From a9f4b02a01125361ca9f03e8398340c2b114e525 Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Wed, 14 Jun 2023 13:41:47 +0300 Subject: [PATCH 14/24] Update docker-compose.yaml --- healenium/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index 548bd46..b5716ac 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.3.3 + image: healenium/hlm-backend:3.3.4 container_name: healenium restart: on-failure ports: From 9c44eeb2bc6f8522618a23d1558ba8b967aeab35 Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Fri, 16 Jun 2023 17:25:04 +0300 Subject: [PATCH 15/24] Update docker-compose-selenium-grid.yaml --- healenium/docker-compose-selenium-grid.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/healenium/docker-compose-selenium-grid.yaml b/healenium/docker-compose-selenium-grid.yaml index 033a0bf..cda0a87 100644 --- a/healenium/docker-compose-selenium-grid.yaml +++ b/healenium/docker-compose-selenium-grid.yaml @@ -47,7 +47,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.3.3 + image: healenium/hlm-proxy:1.3.4 container_name: hlm-proxy restart: on-failure ports: From 223ae3b1e6da6276ac30f3aac4fb9c1f9da4faf9 Mon Sep 17 00:00:00 2001 From: Alex-Reif <69298932+Alex-Reif@users.noreply.github.com> Date: Fri, 16 Jun 2023 17:25:19 +0300 Subject: [PATCH 16/24] Update docker-compose.yaml --- healenium/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index b5716ac..51c853b 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -47,7 +47,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.3.3 + image: healenium/hlm-proxy:1.3.4 container_name: hlm-proxy restart: on-failure ports: From 94e5430a49754f7b801e22a3bf4da8372b47b4b2 Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Mon, 7 Aug 2023 23:46:10 +0300 Subject: [PATCH 17/24] Update readme --- README.md | 11 +++------ src/main/pages/callback_page.py | 7 +----- src/main/pages/testenv_page.py | 8 ++----- tests/test_semantic.py | 24 +++++++++---------- tests/test_wait.py | 42 ++++++++++++++++----------------- 5 files changed, 39 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 96bfc0b..3e94a46 100644 --- a/README.md +++ b/README.md @@ -60,13 +60,8 @@ Verify the next images are Up and Running To run using Healenium create RemoteWebDriver with URL ```http://:8085```: ```py - 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) + options = webdriver.ChromeOptions() + self.driver = webdriver.Remote('http://localhost:8085', options=options) ``` ### 3. Run test @@ -89,7 +84,7 @@ 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``` diff --git a/src/main/pages/callback_page.py b/src/main/pages/callback_page.py index b02a498..57b0973 100644 --- a/src/main/pages/callback_page.py +++ b/src/main/pages/callback_page.py @@ -16,12 +16,7 @@ class CallbackPage(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.callbackTestPageUrl) diff --git a/src/main/pages/testenv_page.py b/src/main/pages/testenv_page.py index 0ec5f8a..93a327f 100644 --- a/src/main/pages/testenv_page.py +++ b/src/main/pages/testenv_page.py @@ -8,6 +8,7 @@ class TestEnvPage(BasePage): + __test__ = False submit_btn = 'Submit' submit_form_btn = 'Submit_checkbox' @@ -15,12 +16,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) 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..7dc2310 100644 --- a/tests/test_wait.py +++ b/tests/test_wait.py @@ -1,21 +1,21 @@ -from src.main.pages.markup_page import MarkupPage - - -class TestWait: - - def test_conditional_wait(self): - markup_page=MarkupPage() - - markup_page.open_browser() - markup_page.click_test_button() - markup_page.confirm_alert() - - 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() +# from src.main.pages.markup_page import MarkupPage +# +# +# class TestWait: +# +# # def test_conditional_wait(self): +# # markup_page=MarkupPage() +# # +# # markup_page.open_browser() +# # markup_page.click_test_button() +# # markup_page.confirm_alert() +# # +# # 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() From daa4d946e707bebeb64c6e65b774468178104d70 Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Thu, 14 Sep 2023 19:45:43 +0300 Subject: [PATCH 18/24] Update healenium version --- README.md | 22 +- healenium/LICENSE | 201 ++++++++++++++++++ healenium/README.md | 59 ++++- healenium/docker-compose-appium.yaml | 75 +++++++ ...grid.yaml => docker-compose-selenoid.yaml} | 70 +++--- healenium/docker-compose-web.yaml | 54 +++++ healenium/docker-compose.yaml | 74 +++++-- healenium/{ => selenoid-config}/browsers.json | 20 +- .../selenium-grid/download_services.sh | 12 ++ .../selenium-grid/start_healenium.sh | 38 ++++ .../selenium-grid/stop_healenium.sh | 3 + .../web/download_services.sh | 9 + .../healenium-selector-imitator/.coveragerc | 6 + .../web/healenium-selector-imitator/.flake8 | 8 + .../.github/workflows/python-package.yml | 37 ++++ .../healenium-selector-imitator/.gitignore | 6 + .../healenium-selector-imitator/Dockerfile | 8 + .../web/healenium-selector-imitator/README.md | 70 ++++++ .../web/healenium-selector-imitator/app.py | 55 +++++ .../docker-compose.yml | 7 + .../web/healenium-selector-imitator/mypy.ini | 3 + .../requirements.txt | 2 + .../requirements_dev.txt | 9 + .../src/__init__.py | 0 .../src/datamodel/__init__.py | 5 + .../src/datamodel/imitation_request.py | 13 ++ .../src/datamodel/imitation_response.py | 10 + .../healenium-selector-imitator/src/node.py | 20 ++ .../src/selector.py | 158 ++++++++++++++ .../src/selector_imitator.py | 150 +++++++++++++ .../src/selector_parser.py | 132 ++++++++++++ .../src/selector_to_string.py | 79 +++++++ .../test/__init__.py | 0 .../test/test_api.py | 114 ++++++++++ .../test/test_imitate/__init__.py | 0 .../test_imitate_by_class_name.py | 40 ++++ .../test_imitate_by_css_selector.py | 46 ++++ .../test/test_imitate/test_imitate_by_id.py | 21 ++ .../test_imitate/test_imitate_by_link_text.py | 30 +++ .../test/test_imitate/test_imitate_by_name.py | 34 +++ .../test_imitate_by_partial_link_text.py | 37 ++++ .../test_imitate/test_imitate_by_tag_name.py | 21 ++ .../test_imitate/test_imitate_by_xpath.py | 46 ++++ .../test_imitate_unimplemented.py | 16 ++ .../test/test_integration.py | 86 ++++++++ .../test/test_parser/__init__.py | 0 .../test/test_parser/test_css_parser.py | 66 ++++++ .../test/test_parser/test_xpath_parser.py | 98 +++++++++ .../test/test_selector/__init__.py | 0 .../test_selector_from_string.py | 81 +++++++ .../test_selector/test_selector_to_string.py | 83 ++++++++ .../test/test_selector_to_string/__init__.py | 0 .../test_css_selector_constructor.py | 40 ++++ .../test_xpath_constructor.py | 52 +++++ .../shell-installation/web/start_healenium.sh | 25 +++ .../shell-installation/web/stop_healenium.sh | 3 + 56 files changed, 2262 insertions(+), 92 deletions(-) create mode 100644 healenium/LICENSE create mode 100644 healenium/docker-compose-appium.yaml rename healenium/{docker-compose-selenium-grid.yaml => docker-compose-selenoid.yaml} (59%) create mode 100644 healenium/docker-compose-web.yaml rename healenium/{ => selenoid-config}/browsers.json (50%) create mode 100644 healenium/shell-installation/selenium-grid/download_services.sh create mode 100644 healenium/shell-installation/selenium-grid/start_healenium.sh create mode 100644 healenium/shell-installation/selenium-grid/stop_healenium.sh create mode 100644 healenium/shell-installation/web/download_services.sh create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/.coveragerc create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/.flake8 create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/.github/workflows/python-package.yml create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/.gitignore create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/Dockerfile create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/README.md create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/app.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/docker-compose.yml create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/mypy.ini create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/requirements.txt create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/requirements_dev.txt create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/__init__.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/__init__.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_request.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_response.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/node.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/selector.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/selector_imitator.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/selector_parser.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/selector_to_string.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/__init__.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_api.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/__init__.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_class_name.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_css_selector.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_id.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_link_text.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_name.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_partial_link_text.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_tag_name.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_xpath.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_unimplemented.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_integration.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/__init__.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_css_parser.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_xpath_parser.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/__init__.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_from_string.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_to_string.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/__init__.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_css_selector_constructor.py create mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_xpath_constructor.py create mode 100644 healenium/shell-installation/web/start_healenium.sh create mode 100644 healenium/shell-installation/web/stop_healenium.sh diff --git a/README.md b/README.md index 3e94a46..7264f71 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ 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. Configuration RemoteWebDriver for Healenium](#2-configuration-remotewebdriver-for-healenium) @@ -23,27 +24,28 @@ Go into healenium folder ```sh cd healenium -``` +``` -#### Run Healenium with Selenoid: +#### Run Healenium with Selenium-Grid: +```sh +docker-compose up -d +``` + +#### 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 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..5798f36 --- /dev/null +++ b/healenium/docker-compose-appium.yaml @@ -0,0 +1,75 @@ +version: "3.8" + +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.4.0 + 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.2 + container_name: selector-imitator + restart: on-failure + ports: + - "8000:8000" + networks: + - healenium + + hlm-proxy: + image: healenium/hlm-proxy:1.3.5 + container_name: hlm-proxy + restart: on-failure + ports: + - "8085:8085" + environment: + - RECOVERY_TRIES=1 + - SCORE_CAP=.6 + - HEAL_ENABLED=true + - SELENIUM_SERVER_URL=http://hlm-selenoid:4444/wd/hub + - APPIUM_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-selenoid.yaml similarity index 59% rename from healenium/docker-compose-selenium-grid.yaml rename to healenium/docker-compose-selenoid.yaml index cda0a87..1b9f599 100644 --- a/healenium/docker-compose-selenium-grid.yaml +++ b/healenium/docker-compose-selenoid.yaml @@ -1,4 +1,4 @@ -version: "3.9" +version: "3.8" services: @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.3.4 + image: healenium/hlm-backend:3.4.0 container_name: healenium restart: on-failure ports: @@ -34,6 +34,9 @@ services: - KEY_SELECTOR_URL=false - COLLECT_METRICS=true - HLM_LOG_LEVEL=info + volumes: + - ./screenshots/:/screenshots + - ./logs/:/logs networks: - healenium @@ -47,7 +50,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.3.4 + image: healenium/hlm-proxy:1.3.5 container_name: hlm-proxy restart: on-failure ports: @@ -56,61 +59,38 @@ services: - RECOVERY_TRIES=1 - SCORE_CAP=.6 - HEAL_ENABLED=true - - SELENIUM_SERVER_URL=http://hlm-selenoid:4444/wd/hub + - SELENIUM_SERVER_URL=http://selenoid:4444/wd/hub - APPIUM_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 - 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 + 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: - - SE_EVENT_BUS_HOST=selenium-hub - - SE_EVENT_BUS_PUBLISH_PORT=4442 - - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + - 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 - selenium-hub: - image: selenium/hub:4.3.0 - container_name: selenium-hub + selenoid-ui: + image: aerokube/selenoid-ui:latest-release + restart: on-failure ports: - - "4442:4442" - - "4443:4443" - - "4444:4444" + - "8080:8080" + command: [ "--selenoid-uri", "http://selenoid:4444" ] networks: - healenium diff --git a/healenium/docker-compose-web.yaml b/healenium/docker-compose-web.yaml new file mode 100644 index 0000000..3df5fa1 --- /dev/null +++ b/healenium/docker-compose-web.yaml @@ -0,0 +1,54 @@ +version: "3.8" + +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.4.0 + 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.2 + 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 51c853b..96d2316 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -1,4 +1,4 @@ -version: "3.9" +version: "3.8" services: @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.3.4 + image: healenium/hlm-backend:3.4.0 container_name: healenium restart: on-failure ports: @@ -34,6 +34,9 @@ services: - KEY_SELECTOR_URL=false - COLLECT_METRICS=true - HLM_LOG_LEVEL=info + volumes: + - ./screenshots/:/screenshots + - ./logs/:/logs networks: - healenium @@ -47,7 +50,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.3.4 + image: healenium/hlm-proxy:1.3.5 container_name: hlm-proxy restart: on-failure ports: @@ -56,37 +59,66 @@ services: - RECOVERY_TRIES=1 - SCORE_CAP=.6 - HEAL_ENABLED=true - - SELENIUM_SERVER_URL=http://hlm-selenoid:4444/wd/hub + - SELENIUM_SERVER_URL=http://selenium-hub:4444/wd/hub - APPIUM_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 - 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..7749340 --- /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.0" +HLM_PROXY_VERSION="1.3.5" + +# 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..90d8e87 --- /dev/null +++ b/healenium/shell-installation/selenium-grid/start_healenium.sh @@ -0,0 +1,38 @@ +#!/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 +APPIUM_SERVER_URL=http://localhost:4723/wd/hub +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 APPIUM_SERVER_URL=$APPIUM_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..e13a8f6 --- /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.0" + +# 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/healenium-selector-imitator/.coveragerc b/healenium/shell-installation/web/healenium-selector-imitator/.coveragerc new file mode 100644 index 0000000..521e972 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/.coveragerc @@ -0,0 +1,6 @@ +# .coveragerc to control coverage.py +[run] +omit = + */site-packages/* + */distutils/* + tests/* \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/.flake8 b/healenium/shell-installation/web/healenium-selector-imitator/.flake8 new file mode 100644 index 0000000..2aa8cb4 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/.flake8 @@ -0,0 +1,8 @@ +[flake8] +max-line-length = 88 +exclude = + .git + .idea + .pytest_cache + env + dist \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/.github/workflows/python-package.yml b/healenium/shell-installation/web/healenium-selector-imitator/.github/workflows/python-package.yml new file mode 100644 index 0000000..e4d0f13 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/.github/workflows/python-package.yml @@ -0,0 +1,37 @@ +name: Python package + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.7 + uses: actions/setup-python@v2 + with: + python-version: '3.7' + - name: Install dependencies + run: | + pip install -r requirements_dev.txt + - name: Check types with mypy + run: | + mypy src app.py + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Lint with black + run: | + black --check . + - name: Test with pytest + run: | + pytest diff --git a/healenium/shell-installation/web/healenium-selector-imitator/.gitignore b/healenium/shell-installation/web/healenium-selector-imitator/.gitignore new file mode 100644 index 0000000..2149682 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/.gitignore @@ -0,0 +1,6 @@ +env +.idea +__pycache__ +.coverage +htmlcov +dist \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/Dockerfile b/healenium/shell-installation/web/healenium-selector-imitator/Dockerfile new file mode 100644 index 0000000..b160254 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.7-slim-stretch + +COPY ./requirements.txt ./requirements.txt +COPY ./dist ./ + +RUN pip install -r requirements.txt + +CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/README.md b/healenium/shell-installation/web/healenium-selector-imitator/README.md new file mode 100644 index 0000000..71f2c1f --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/README.md @@ -0,0 +1,70 @@ +# Healenium selector imitator + +Selector imitator tries to reconstruct a user selector, changing only fields that the user modified in HTML. It works with the original selector (and its type) and target node (so it should be applied after the best node is already found). It proposes possible healed selectors or raises an error. +Proposed selectors are not guaranteed to find a unique web element. Uniqueness must be checked outside of the service with a selenium driver. + +1. [Example request and response](#example) +2. [Image and container resources consumption](#resources) +3. [Installation with Docker](#installation) +4. [Creating your own image from Dockerfile](#image) +5. [Local testing](#testing) + +### Example request and response + +Here is an example request. You can try out different requests with Swagger after the [installation](#installation). +![image](https://user-images.githubusercontent.com/40484210/127833016-10da747f-ae4d-480f-9624-ec1266cbbb25.png) +![image](https://user-images.githubusercontent.com/40484210/127833088-59eeced9-17c3-4b60-b1ee-f97d4421ff33.png) + + +### Image and container resources consumption +![image](https://user-images.githubusercontent.com/40484210/123598005-b7c7ff00-d7fc-11eb-9be6-fa20c181bb47.png) +![image](https://user-images.githubusercontent.com/40484210/123598058-c3b3c100-d7fc-11eb-85d9-380bacd53d6a.png) + + +### Installation with Docker +Run the following command to install and use Healenium selector imitator as a stand-alone service (you'll need docker installed): +``` +docker compose up +``` +Now you can access an API at http://localhost:8000/ +Check http://localhost:8000/docs for Swagger documentation. + +### Creating your own image from Dockerfile +If you wish to make some changes to the code and test them in Docker environment, you will need to create an image. +Run these commands from the repository directory, change the version if needed (you'll need docker and pyarmor installed): +``` +pyarmor obfuscate --platform linux.x86_64.7 --recursive --output dist/src src/__init__.py +pyarmor obfuscate --platform linux.x86_64.7 --exact app.py +docker build -t healenium/hlm-selector-imitator:1 . +docker run -d -p 8000:8000 healenium/hlm-selector-imitator:1 +``` + +### Local testing +To test or lint locally, create a virtual environment with Pyhton 3.7 and install packages from requirements_dev.txt + +Test with [pytest](https://docs.pytest.org/en/6.2.x/): +``` +pytest +``` + +Get [coverage](https://coverage.readthedocs.io/en/coverage-5.5/#) report: +``` +coverage run -m pytest +coverage report -m +coverage html +``` + +Check types with [mypy](https://mypy.readthedocs.io/en/stable/): +``` +mypy src app.py +``` + +Lint with [flake8](https://flake8.pycqa.org/en/latest/): +``` +flake8 +``` + +Format code with [black](https://github.com/psf/black): +``` +black . +``` diff --git a/healenium/shell-installation/web/healenium-selector-imitator/app.py b/healenium/shell-installation/web/healenium-selector-imitator/app.py new file mode 100644 index 0000000..f08a81d --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/app.py @@ -0,0 +1,55 @@ +import os +import uvicorn + +from fastapi import FastAPI, Request +from fastapi.responses import JSONResponse +from src.datamodel import ImitationRequestModel, ImitationResponseModel +from src.selector import Selector +from src.selector_imitator import SelectorImitator, ImitationError +from src.selector_parser import ParsingError +from typing import List + + +app = FastAPI() + + +@app.exception_handler(ImitationError) +async def imitation_error_handler( + request: Request, exc: ImitationError +) -> JSONResponse: + return JSONResponse( + status_code=422, + content={"detail": [{"msg": f"Unable to imitate the user selector: {exc}"}]}, + ) + + +@app.exception_handler(ParsingError) +async def parsing_error_handler(request: Request, exc: ParsingError) -> JSONResponse: + return JSONResponse( + status_code=422, + content={"detail": [{"msg": f"Unable to parse the user selector: {exc}"}]}, + ) + + +@app.get("/") +def main() -> str: + return "this is an entry point of the selector imitator" + + +@app.post("/imitate", response_model=List[ImitationResponseModel]) +async def imitate(request: ImitationRequestModel) -> List[ImitationResponseModel]: + user_selector = Selector.from_type_and_value( + selector_type=request.user_selector.type, value=request.user_selector.value + ) + imitator = SelectorImitator(user_selector, request.target_node) + result = [ + ImitationResponseModel( + selector_type=selector.selector_type, selector_value=str(selector) + ) + for selector in imitator.imitate() + ] + return result + + +if __name__ == "__main__": + uvicorn.run("app:app", host="0.0.0.0", port=os.getenv("PORT", 8000)) diff --git a/healenium/shell-installation/web/healenium-selector-imitator/docker-compose.yml b/healenium/shell-installation/web/healenium-selector-imitator/docker-compose.yml new file mode 100644 index 0000000..0a8b649 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/docker-compose.yml @@ -0,0 +1,7 @@ +version: "3.9" +services: + selector-imitator: + image: "healenium/hlm-selector-imitator:1" + restart: on-failure + ports: + - "8000:8000" diff --git a/healenium/shell-installation/web/healenium-selector-imitator/mypy.ini b/healenium/shell-installation/web/healenium-selector-imitator/mypy.ini new file mode 100644 index 0000000..3e81927 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/mypy.ini @@ -0,0 +1,3 @@ +[mypy] +ignore_missing_imports = True +strict = True \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/requirements.txt b/healenium/shell-installation/web/healenium-selector-imitator/requirements.txt new file mode 100644 index 0000000..f185c39 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/requirements.txt @@ -0,0 +1,2 @@ +fastapi==0.65.2 +uvicorn==0.13.4 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/requirements_dev.txt b/healenium/shell-installation/web/healenium-selector-imitator/requirements_dev.txt new file mode 100644 index 0000000..21f3a76 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/requirements_dev.txt @@ -0,0 +1,9 @@ +black==21.6b0 +coverage==5.5 +fastapi==0.65.2 +flake8==3.9.2 +mypy==0.910 +pyarmor==6.7.3 +pytest==6.2.4 +requests==2.25.1 +uvicorn==0.13.4 \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/__init__.py new file mode 100644 index 0000000..b689ec3 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/__init__.py @@ -0,0 +1,5 @@ +from .imitation_request import ImitationRequestModel +from .imitation_response import ImitationResponseModel + + +__all__ = ["ImitationRequestModel", "ImitationResponseModel"] diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_request.py b/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_request.py new file mode 100644 index 0000000..01a24bd --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_request.py @@ -0,0 +1,13 @@ +from pydantic import BaseModel, Field +from src.node import Node +from src.selector import SelectorType + + +class UserSelector(BaseModel): + type: SelectorType + value: str + + +class ImitationRequestModel(BaseModel): + user_selector: UserSelector = Field(..., alias="userSelector") + target_node: Node = Field(..., alias="targetNode") diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_response.py b/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_response.py new file mode 100644 index 0000000..f36a01b --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_response.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel, Field +from src.selector import SelectorType + + +class ImitationResponseModel(BaseModel): + selector_type: SelectorType = Field(..., alias="type") + selector_value: str = Field(..., alias="value") + + class Config: + allow_population_by_field_name = True diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/node.py b/healenium/shell-installation/web/healenium-selector-imitator/src/node.py new file mode 100644 index 0000000..b25883b --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/src/node.py @@ -0,0 +1,20 @@ +from pydantic import BaseModel, Field, validator +from typing import Optional, List, Dict, Union + + +class Node(BaseModel): + tag: str = "" + id: str = "" + classes: List[str] = Field(default_factory=list) + index: Optional[int] = None + other_attributes: Dict[str, str] = Field(default_factory=dict, alias="other") + inner_text: str = Field("", alias="innerText") + + class Config: + allow_population_by_field_name = True + + @validator("classes", pre=True) + def split_classes(cls, value: Union[str, List[str]]) -> List[str]: + if isinstance(value, str): + return value.split() + return value diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/selector.py b/healenium/shell-installation/web/healenium-selector-imitator/src/selector.py new file mode 100644 index 0000000..29cfcfa --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/src/selector.py @@ -0,0 +1,158 @@ +from dataclasses import dataclass +from enum import Enum +from .selector_parser import CSSSelectorParser, XPathParser +from .selector_to_string import CSSSelectorConstructor, XPathConstructor +from typing import Optional, List, Dict + + +class SelectorType(str, Enum): + BY_CLASS_NAME = "By.className" + BY_CSS_SELECTOR = "By.cssSelector" + BY_ID = "By.id" + BY_LINK_TEXT = "By.linkText" + BY_NAME = "By.name" + BY_PARTIAL_LINK_TEXT = "By.partialLinkText" + BY_TAG_NAME = "By.tagName" + BY_XPATH = "By.xpath" + + +@dataclass +class Selector: + selector_type: SelectorType + tag: Optional[str] = None + id: Optional[str] = None + classes: Optional[List[str]] = None + index: Optional[int] = None + other_attributes: Optional[Dict[str, str]] = None + inner_text: Optional[str] = None + split_classes: bool = False + + @classmethod + def from_type_and_value(cls, selector_type: SelectorType, value: str) -> "Selector": + if selector_type is SelectorType.BY_CLASS_NAME: + return cls.from_class_name(value) + elif selector_type is SelectorType.BY_CSS_SELECTOR: + return cls.from_css(value) + elif selector_type is SelectorType.BY_ID: + return cls.from_id(value) + elif selector_type is SelectorType.BY_LINK_TEXT: + return cls.from_link_text(value) + elif selector_type is SelectorType.BY_NAME: + return cls.from_name(value) + elif selector_type is SelectorType.BY_PARTIAL_LINK_TEXT: + return cls.from_partial_link_text(value) + elif selector_type is SelectorType.BY_TAG_NAME: + return cls.from_tag_name(value) + elif selector_type is SelectorType.BY_XPATH: + return cls.from_xpath(value) + else: + raise ValueError(f"Invalid selector type: {selector_type}") + + @classmethod + def from_class_name(cls, class_name: str) -> "Selector": + return cls(selector_type=SelectorType.BY_CLASS_NAME, classes=[class_name]) + + @classmethod + def from_css(cls, css_selector: str) -> "Selector": + parser = CSSSelectorParser(css_selector) + return cls( + selector_type=SelectorType.BY_CSS_SELECTOR, + tag=parser.get_tag() or None, + id=parser.get_id() or None, + classes=parser.get_classes() or None, + other_attributes=parser.get_attributes() or None, + ) + + @classmethod + def from_id(cls, element_id: str) -> "Selector": + return cls(selector_type=SelectorType.BY_ID, id=element_id) + + @classmethod + def from_link_text(cls, link_text: str) -> "Selector": + return cls(selector_type=SelectorType.BY_LINK_TEXT, inner_text=link_text) + + @classmethod + def from_name(cls, name: str) -> "Selector": + return cls(selector_type=SelectorType.BY_NAME, other_attributes={"name": name}) + + @classmethod + def from_partial_link_text(cls, partial_link_text: str) -> "Selector": + return cls( + selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, + inner_text=partial_link_text, + ) + + @classmethod + def from_tag_name(cls, tag_name: str) -> "Selector": + return cls(selector_type=SelectorType.BY_TAG_NAME, tag=tag_name) + + @classmethod + def from_xpath(cls, xpath_selector: str) -> "Selector": + parser = XPathParser(xpath_selector) + return cls( + selector_type=SelectorType.BY_XPATH, + tag=parser.get_tag() or None, + id=parser.get_id() or None, + classes=parser.get_classes() or None, + index=parser.get_index(), + other_attributes=parser.get_attributes() or None, + inner_text=parser.get_inner_text() or None, + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Selector): + return False + return ( + self.selector_type == other.selector_type + and self.tag == other.tag + and self.id == other.id + and set(self.classes or []) == set(other.classes or []) + and self.index == other.index + and self.other_attributes == other.other_attributes + and self.inner_text == other.inner_text + ) + + def __str__(self) -> str: + if self.selector_type is SelectorType.BY_CLASS_NAME: + if self.classes is None or len(self.classes) == 0: + raise ValueError( + "BY_CLASS_NAME selector must contain one class name, none provided." + ) + if len(self.classes) == 1: + return self.classes[0] + else: + raise ValueError( + "Ambiguous BY_CLASS_NAME selector. " + "Only one class allowed for this selector type." + ) + elif self.selector_type is SelectorType.BY_CSS_SELECTOR: + return CSSSelectorConstructor( + tag=self.tag, + element_id=self.id, + classes=self.classes, + other_attributes=self.other_attributes, + ).get_string_representation() + elif self.selector_type is SelectorType.BY_ID: + return self.id if self.id is not None else "" + elif self.selector_type is SelectorType.BY_LINK_TEXT: + return self.inner_text if self.inner_text is not None else "" + elif self.selector_type is SelectorType.BY_NAME: + if self.other_attributes is not None and "name" in self.other_attributes: + return self.other_attributes["name"] + else: + raise ValueError("BY_NAME selector must contain name attribute.") + elif self.selector_type is SelectorType.BY_PARTIAL_LINK_TEXT: + return self.inner_text if self.inner_text is not None else "" + elif self.selector_type is SelectorType.BY_TAG_NAME: + return self.tag if self.tag is not None else "" + elif self.selector_type is SelectorType.BY_XPATH: + return XPathConstructor( + tag=self.tag, + element_id=self.id, + classes=self.classes, + other_attributes=self.other_attributes, + index=self.index, + inner_text=self.inner_text, + ).get_string_representation(split_classes=self.split_classes) + else: + return "" diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/selector_imitator.py b/healenium/shell-installation/web/healenium-selector-imitator/src/selector_imitator.py new file mode 100644 index 0000000..ebfa4f9 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/src/selector_imitator.py @@ -0,0 +1,150 @@ +from .node import Node +from .selector import Selector, SelectorType +from typing import List + + +class ImitationError(Exception): + pass + + +class SelectorImitator: + def __init__(self, user_selector: Selector, target_node: Node): + self.user_selector = user_selector + self.target_node = target_node + + def _imitate_class_name(self) -> List[Selector]: + if self.target_node.classes: + return [ + Selector( + selector_type=SelectorType.BY_CLASS_NAME, + classes=[target_class], + ) + for target_class in self.target_node.classes + ] + else: + raise ImitationError("Target node does not belong to any class.") + + def _imitate_css_or_xpath(self) -> Selector: + target_selector = Selector(selector_type=self.user_selector.selector_type) + if self.user_selector.tag is not None: + if self.target_node.tag: + target_selector.tag = self.target_node.tag + else: + raise ImitationError("Target node does not have any tag.") + if self.user_selector.id is not None: + if self.target_node.id: + target_selector.id = self.target_node.id + else: + raise ImitationError("Target node does not have any id.") + if self.user_selector.classes is not None: + if self.target_node.classes: + target_selector.classes = [] + some_class_changed = False + for cls in self.user_selector.classes: + if cls in self.target_node.classes: + target_selector.classes.append(cls) + else: + some_class_changed = True + break + if some_class_changed: + target_selector.classes = self.target_node.classes + else: + raise ImitationError("Target node does not belong to any classes.") + target_selector.split_classes = ( + target_selector.classes != self.target_node.classes + ) + if self.user_selector.index is not None: + if self.target_node.index: + target_selector.index = self.target_node.index + else: + raise ImitationError("Target node does not have any index.") + if self.user_selector.inner_text is not None: + if self.target_node.inner_text: + target_selector.inner_text = self.target_node.inner_text + else: + raise ImitationError("Target node does not have any inner text.") + if self.user_selector.other_attributes is not None: + target_selector.other_attributes = {} + for attribute in self.user_selector.other_attributes: + if attribute in self.target_node.other_attributes: + target_selector.other_attributes[ + attribute + ] = self.target_node.other_attributes[attribute] + else: + raise ImitationError( + f"Target node does not have an attribute {attribute}." + ) + return target_selector + + def _imitate_id(self) -> Selector: + if self.target_node.id: + return Selector(selector_type=SelectorType.BY_ID, id=self.target_node.id) + else: + raise ImitationError("Target node does not have an id.") + + def _imitate_link_text(self) -> Selector: + if self.target_node.tag != "a": + raise ImitationError( + "Target node is not an anchor tag, " + "so selector by link text is not applicable." + ) + if self.target_node.inner_text: + return Selector( + selector_type=self.user_selector.selector_type, + inner_text=self.target_node.inner_text, + ) + else: + raise ImitationError("Target node does not have a link text.") + + def _imitate_name(self) -> Selector: + if "name" in self.target_node.other_attributes: + if ( + self.user_selector.other_attributes is not None + and "name" in self.user_selector.other_attributes + ): + return Selector( + selector_type=SelectorType.BY_NAME, + other_attributes={ + "name": self.target_node.other_attributes["name"] + }, + ) + else: + raise ImitationError( + "Invalid user selector: does not contain name attribute, " + "while type is BY_NAME." + ) + else: + raise ImitationError("Target node does not have a name attribute.") + + def _by_tag_name(self) -> Selector: + if self.target_node.tag: + return Selector( + selector_type=SelectorType.BY_TAG_NAME, tag=self.target_node.tag + ) + else: + raise ImitationError("Target node does not have a tag name.") + + def imitate(self) -> List[Selector]: + """Return a list of possible selectors for a target node that imitates a user selector. + Raise ImitationError if the target node cannot be imitated. + """ + if self.user_selector.selector_type is SelectorType.BY_CLASS_NAME: + return self._imitate_class_name() + elif self.user_selector.selector_type in [ + SelectorType.BY_CSS_SELECTOR, + SelectorType.BY_XPATH, + ]: + return [self._imitate_css_or_xpath()] + elif self.user_selector.selector_type is SelectorType.BY_ID: + return [self._imitate_id()] + elif self.user_selector.selector_type in [ + SelectorType.BY_LINK_TEXT, + SelectorType.BY_PARTIAL_LINK_TEXT, + ]: + return [self._imitate_link_text()] + elif self.user_selector.selector_type is SelectorType.BY_NAME: + return [self._imitate_name()] + elif self.user_selector.selector_type is SelectorType.BY_TAG_NAME: + return [self._by_tag_name()] + else: + raise ImitationError("Imitation for user selector type is not implemented.") diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/selector_parser.py b/healenium/shell-installation/web/healenium-selector-imitator/src/selector_parser.py new file mode 100644 index 0000000..dea3347 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/src/selector_parser.py @@ -0,0 +1,132 @@ +import re + +from typing import List, Dict, Optional + + +class ParsingError(Exception): + pass + + +class ParsingUtils: + @staticmethod + def remove_quoted_text(text: str) -> str: + result = text + single_quote_expression = re.compile("'.*'") + double_quote_expression = re.compile('".*"') + for expression in [single_quote_expression, double_quote_expression]: + while True: + search_result = expression.search(result) + if search_result is not None: + idx_from, idx_to = search_result.span() + result = result[:idx_from] + result[idx_to:] + else: + break + return result + + +class CSSSelectorParser: + def __init__(self, selector: str): + self.selector = selector + self.validate() + + def validate(self) -> None: + expression = re.compile(r"^([\w-]*)(\.[\w-]+|#[\w-]+|\[.+])*$") + if expression.match(self.selector) is None: + raise ParsingError("Cannot parse CSS selector.") + + def get_tag(self) -> str: + expression = re.compile(r"^[\w-]+") + search_result = expression.search(self.selector) + if search_result is None: + return "" + else: + return search_result.group() + + def get_id(self) -> str: + expression = re.compile(r"#([\w-]+)") + search_result = expression.search( + ParsingUtils.remove_quoted_text(self.selector) + ) + if search_result is None: + return "" + else: + return search_result.group(1) + + def get_classes(self) -> List[str]: + expression = re.compile(r"\.([\w-]+)") + return expression.findall(ParsingUtils.remove_quoted_text(self.selector)) + + def get_attributes(self) -> Dict[str, str]: + attributes = {} + raw_attributes = re.compile(r"\[[^\[\]]+]").findall(self.selector) + for attribute in raw_attributes: + attribute_expression = re.compile(r"""\[([\w-]+)=('.*'|".*")]""") + attribute_match = attribute_expression.match(attribute) + if attribute_match is not None: + attributes[attribute_match.group(1)] = ( + attribute_match.group(2).strip("'").strip('"') + ) + return attributes + + +class XPathParser: + def __init__(self, selector: str): + self.selector = selector + self.validate() + + def validate(self) -> None: + expression = re.compile(r"^//([\w-]*|\*)(\[.+])*$") + if expression.match(self.selector) is None: + raise ParsingError("Cannot parse XPath selector.") + + def get_tag(self) -> str: + expression = re.compile(r"^//([\w-]+)") + search_result = expression.search(self.selector) + if search_result is None: + return "" + else: + return search_result.group(1) + + def get_id(self) -> str: + expression = re.compile(r"""@id=('[\w-]+'|"[\w-]+")""") + search_result = expression.search(self.selector) + if search_result is None: + return "" + else: + return search_result.group(1).strip('"').strip("'") + + def get_classes(self) -> List[str]: + expression_all_classes = r"""@class=('[ \w-]+'|"[ \w-]+")""" + expression_contains = r"""contains\(@class,('[ \w-]+'|"[ \w-]+")\)""" + for expression in [expression_all_classes, expression_contains]: + search_result = re.compile(expression).search(self.selector) + if search_result is not None: + return search_result.group(1).strip('"').strip("'").split(" ") + return [] + + def get_attributes(self) -> Dict[str, str]: + attributes = {} + attribute_expression = re.compile(r"""@([\w-]+)=('[^']*'|"[^"]*")""") + raw_attributes = attribute_expression.findall(self.selector) + for attr_name, attr_value in raw_attributes: + if attr_name not in ["class", "id"]: + attributes[attr_name] = attr_value.strip("'").strip('"') + return attributes + + def get_index(self) -> Optional[int]: + expression = re.compile(r"""\[(\d)+]""") + search_result = expression.search( + ParsingUtils.remove_quoted_text(self.selector) + ) + if search_result is None: + return None + else: + return int(search_result.group(1)) + + def get_inner_text(self) -> str: + expression = re.compile(r"""text\(\)=('[^']*'|"[^"]*")""") + search_result = expression.search(self.selector) + if search_result is None: + return "" + else: + return search_result.group(1)[1:-1] diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/selector_to_string.py b/healenium/shell-installation/web/healenium-selector-imitator/src/selector_to_string.py new file mode 100644 index 0000000..2ea9492 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/src/selector_to_string.py @@ -0,0 +1,79 @@ +from typing import List, Dict, Optional + + +class CSSSelectorConstructor: + def __init__( + self, + tag: Optional[str] = None, + element_id: Optional[str] = None, + classes: Optional[List[str]] = None, + other_attributes: Optional[Dict[str, str]] = None, + ): + self.tag = tag + self.element_id = element_id + if classes is not None: + self.classes = classes + else: + self.classes = [] + if other_attributes is not None: + self.other_attributes = other_attributes + else: + self.other_attributes = {} + + def get_string_representation(self) -> str: + result = "" + if self.tag is not None: + result += self.tag + if self.element_id is not None: + result += f"#{self.element_id}" + for class_name in self.classes: + result += f".{class_name}" + for attr_name, attr_value in self.other_attributes.items(): + result += f"[{attr_name}='{attr_value}']" + return result + + +class XPathConstructor: + def __init__( + self, + tag: Optional[str] = None, + element_id: Optional[str] = None, + classes: Optional[List[str]] = None, + other_attributes: Optional[Dict[str, str]] = None, + index: Optional[int] = None, + inner_text: Optional[str] = None, + ): + self.tag = tag + self.element_id = element_id + if classes is not None: + self.classes = classes + else: + self.classes = [] + if other_attributes is not None: + self.other_attributes = other_attributes + else: + self.other_attributes = {} + self.index = index + self.inner_text = inner_text + + def get_string_representation(self, split_classes: bool = False) -> str: + result = "//" + if self.tag is None: + result += "*" + else: + result += self.tag + if self.element_id is not None: + result += f"[@id='{self.element_id}']" + if split_classes: + for classname in self.classes: + result += f"[contains(@class, '{classname}')]" + elif self.classes: + merged_classes = " ".join(self.classes) + result += f"[@class='{merged_classes}']" + for attr_name, attr_value in self.other_attributes.items(): + result += f"[@{attr_name}='{attr_value}']" + if self.inner_text is not None: + result += f"[text()='{self.inner_text}']" + if self.index is not None: + result += f"[{self.index}]" + return result diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_api.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_api.py new file mode 100644 index 0000000..7e25754 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_api.py @@ -0,0 +1,114 @@ +import pytest + +from app import app +from fastapi.testclient import TestClient +from typing import List + + +@pytest.fixture() +def user_selector() -> dict: + return {"type": "By.xpath", "value": "//*[@value='Log In']"} + + +@pytest.fixture() +def user_selector_invalid_value() -> dict: + return {"type": "By.xpath", "value": "hello, world!"} + + +@pytest.fixture() +def target_node() -> dict: + return { + "tag": "input", + "classes": "fadeIn fourth", + "other": { + "_ngcontent-wvw-c3": "", + "type": "button", + "value": "Log In New", + }, + "parent": None, + "children": [], + } + + +@pytest.fixture() +def target_node_no_value() -> dict: + return { + "tag": "input", + "classes": "fadeIn fourth", + "other": { + "_ngcontent-wvw-c3": "", + "type": "button", + }, + "parent": None, + "children": [], + } + + +@pytest.fixture() +def expected_response() -> List[dict]: + return [{"type": "By.xpath", "value": "//*[@value='Log In New']"}] + + +@pytest.fixture() +def expected_response_imitation_error() -> dict: + return { + "detail": [ + { + "msg": "Unable to imitate the user selector: " + "Target node does not have an attribute value." + } + ] + } + + +@pytest.fixture() +def expected_response_parsing_error() -> dict: + return { + "detail": [ + { + "msg": "Unable to parse the user selector: " + "Cannot parse XPath selector." + } + ] + } + + +def test_main(): + with TestClient(app) as client: + response = client.get("/") + assert response.status_code == 200 + + +def test_imitate(user_selector: dict, target_node: dict, expected_response: List[dict]): + request_data = {"userSelector": user_selector, "targetNode": target_node} + with TestClient(app) as client: + response = client.post("/imitate", json=request_data) + assert response.status_code == 200 + assert response.json() == expected_response + + +def test_imitation_error( + user_selector: dict, + target_node_no_value: dict, + expected_response_imitation_error: List[dict], +): + request_data = {"userSelector": user_selector, "targetNode": target_node_no_value} + with TestClient(app) as client: + response = client.post("/imitate", json=request_data) + assert response.status_code == 422 + assert response.json() == expected_response_imitation_error + + +def test_parsing_error( + user_selector_invalid_value: dict, + target_node: dict, + expected_response_parsing_error: List[dict], +): + request_data = { + "userSelector": user_selector_invalid_value, + "targetNode": target_node, + } + with TestClient(app) as client: + response = client.post("/imitate", json=request_data) + assert response.status_code == 422 + assert response.json() == expected_response_parsing_error diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_class_name.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_class_name.py new file mode 100644 index 0000000..f2b9b59 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_class_name.py @@ -0,0 +1,40 @@ +import pytest + +from src.node import Node +from src.selector import Selector, SelectorType +from src.selector_imitator import SelectorImitator, ImitationError + + +def test_imitate_by_class_name(): + user_selector = Selector( + selector_type=SelectorType.BY_CLASS_NAME, classes=["class1"] + ) + target_node = Node(classes=["class2"]) + expected_result = Selector( + selector_type=SelectorType.BY_CLASS_NAME, classes=["class2"] + ) + imitated_selectors = SelectorImitator(user_selector, target_node).imitate() + assert len(imitated_selectors) == 1 + assert imitated_selectors[0] == expected_result + + +def test_imitate_by_class_name_two_classes(): + user_selector = Selector( + selector_type=SelectorType.BY_CLASS_NAME, classes=["class1"] + ) + target_node = Node(classes=["class2", "class3"]) + expected_result = [ + Selector(selector_type=SelectorType.BY_CLASS_NAME, classes=["class2"]), + Selector(selector_type=SelectorType.BY_CLASS_NAME, classes=["class3"]), + ] + imitated_selectors = SelectorImitator(user_selector, target_node).imitate() + assert expected_result == imitated_selectors + + +def test_imitate_by_class_name_invalid_target(): + user_selector = Selector( + selector_type=SelectorType.BY_CLASS_NAME, classes=["class1"] + ) + target_node = Node(tag="p", id="some_id") + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_css_selector.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_css_selector.py new file mode 100644 index 0000000..f391b27 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_css_selector.py @@ -0,0 +1,46 @@ +import pytest + +from src.node import Node +from src.selector import Selector, SelectorType +from src.selector_imitator import SelectorImitator, ImitationError + + +def test_imitate_by_css_selector(): + user_selector = Selector( + selector_type=SelectorType.BY_CSS_SELECTOR, + tag="img", + other_attributes={"name": "some_name"}, + ) + target_node = Node(tag="img", other_attributes={"name": "name2"}) + expected_result = Selector( + selector_type=SelectorType.BY_CSS_SELECTOR, + tag="img", + other_attributes={"name": "name2"}, + ) + imitated_selectors = SelectorImitator(user_selector, target_node).imitate() + assert len(imitated_selectors) == 1 + assert imitated_selectors[0] == expected_result + + +def test_imitate_by_css_selector_invalid_attributes(): + user_selector = Selector( + selector_type=SelectorType.BY_CSS_SELECTOR, + classes=["class1"], + other_attributes={"name": "some_name"}, + ) + target_node = Node( + classes=["class2", "class3"], other_attributes={"src": "img.png"} + ) + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() + + +def test_imitate_by_css_selector_invalid_target(): + user_selector = Selector( + selector_type=SelectorType.BY_CSS_SELECTOR, + tag="img", + other_attributes={"name": "some_name"}, + ) + target_node = Node(other_attributes={"name": "some_name"}) + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_id.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_id.py new file mode 100644 index 0000000..db36557 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_id.py @@ -0,0 +1,21 @@ +import pytest + +from src.node import Node +from src.selector import Selector, SelectorType +from src.selector_imitator import SelectorImitator, ImitationError + + +def test_imitate_by_id(): + user_selector = Selector(selector_type=SelectorType.BY_ID, id="element1") + target_node = Node(tag="h1", id="element2") + expected_result = Selector(selector_type=SelectorType.BY_ID, id="element2") + imitated_selectors = SelectorImitator(user_selector, target_node).imitate() + assert len(imitated_selectors) == 1 + assert imitated_selectors[0] == expected_result + + +def test_imitate_by_id_invalid_target(): + user_selector = Selector(selector_type=SelectorType.BY_ID, id="element1") + target_node = Node(tag="p", other_attributes={"name": "element1"}) + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_link_text.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_link_text.py new file mode 100644 index 0000000..9f3aea6 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_link_text.py @@ -0,0 +1,30 @@ +import pytest + +from src.node import Node +from src.selector import Selector, SelectorType +from src.selector_imitator import SelectorImitator, ImitationError + + +def test_imitate_by_link_text(): + user_selector = Selector(selector_type=SelectorType.BY_LINK_TEXT, inner_text="link") + target_node = Node(tag="a", inner_text="link to external page") + expected_result = Selector( + selector_type=SelectorType.BY_LINK_TEXT, inner_text="link to external page" + ) + imitated_selectors = SelectorImitator(user_selector, target_node).imitate() + assert len(imitated_selectors) == 1 + assert imitated_selectors[0] == expected_result + + +def test_imitate_by_link_text_not_anchor(): + user_selector = Selector(selector_type=SelectorType.BY_LINK_TEXT, inner_text="link") + target_node = Node(tag="p", inner_text="link to external page") + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() + + +def test_imitate_by_link_text_invalid_target(): + user_selector = Selector(selector_type=SelectorType.BY_LINK_TEXT, inner_text="link") + target_node = Node(tag="a", inner_text="") + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_name.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_name.py new file mode 100644 index 0000000..214afbc --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_name.py @@ -0,0 +1,34 @@ +import pytest + +from src.node import Node +from src.selector import Selector, SelectorType +from src.selector_imitator import SelectorImitator, ImitationError + + +def test_imitate_by_name(): + user_selector = Selector( + selector_type=SelectorType.BY_NAME, other_attributes={"name": "element1"} + ) + target_node = Node(tag="h1", other_attributes={"name": "element_1"}) + expected_result = Selector( + selector_type=SelectorType.BY_NAME, other_attributes={"name": "element_1"} + ) + imitated_selectors = SelectorImitator(user_selector, target_node).imitate() + assert len(imitated_selectors) == 1 + assert imitated_selectors[0] == expected_result + + +def test_imitate_by_name_invalid_target(): + user_selector = Selector( + selector_type=SelectorType.BY_NAME, other_attributes={"name": "element1"} + ) + target_node = Node(tag="h1") + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() + + +def test_imitate_by_name_invalid_user_selector(): + user_selector = Selector(selector_type=SelectorType.BY_NAME) + target_node = Node(tag="h1", other_attributes={"name": "element_1"}) + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_partial_link_text.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_partial_link_text.py new file mode 100644 index 0000000..bada68f --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_partial_link_text.py @@ -0,0 +1,37 @@ +import pytest + +from src.node import Node +from src.selector import Selector, SelectorType +from src.selector_imitator import SelectorImitator, ImitationError + + +def test_imitate_by_partial_link_text(): + user_selector = Selector( + selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, inner_text="link" + ) + target_node = Node(tag="a", inner_text="link to external page") + expected_result = Selector( + selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, + inner_text="link to external page", + ) + imitated_selectors = SelectorImitator(user_selector, target_node).imitate() + assert len(imitated_selectors) == 1 + assert imitated_selectors[0] == expected_result + + +def test_imitate_by_partial_link_text_not_anchor(): + user_selector = Selector( + selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, inner_text="link" + ) + target_node = Node(tag="p", inner_text="link to external page") + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() + + +def test_imitate_by_partial_link_text_invalid_target(): + user_selector = Selector( + selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, inner_text="link" + ) + target_node = Node(tag="a", inner_text="") + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_tag_name.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_tag_name.py new file mode 100644 index 0000000..81ac612 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_tag_name.py @@ -0,0 +1,21 @@ +import pytest + +from src.node import Node +from src.selector import Selector, SelectorType +from src.selector_imitator import SelectorImitator, ImitationError + + +def test_imitate_by_tag_name(): + user_selector = Selector(selector_type=SelectorType.BY_TAG_NAME, tag="h1") + target_node = Node(tag="h2", id="element2") + expected_result = Selector(selector_type=SelectorType.BY_TAG_NAME, tag="h2") + imitated_selectors = SelectorImitator(user_selector, target_node).imitate() + assert len(imitated_selectors) == 1 + assert imitated_selectors[0] == expected_result + + +def test_imitate_by_tag_name_invalid_target(): + user_selector = Selector(selector_type=SelectorType.BY_TAG_NAME, tag="h1") + target_node = Node(other_attributes={"name": "element1"}) + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_xpath.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_xpath.py new file mode 100644 index 0000000..092af98 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_xpath.py @@ -0,0 +1,46 @@ +import pytest + +from src.node import Node +from src.selector import Selector, SelectorType +from src.selector_imitator import SelectorImitator, ImitationError + + +def test_imitate_by_xpath(): + user_selector = Selector( + selector_type=SelectorType.BY_XPATH, + tag="img", + other_attributes={"name": "some_name"}, + ) + target_node = Node(tag="img", other_attributes={"name": "name2"}) + expected_result = Selector( + selector_type=SelectorType.BY_XPATH, + tag="img", + other_attributes={"name": "name2"}, + ) + imitated_selectors = SelectorImitator(user_selector, target_node).imitate() + assert len(imitated_selectors) == 1 + assert imitated_selectors[0] == expected_result + + +def test_imitate_by_xpath_invalid_attributes(): + user_selector = Selector( + selector_type=SelectorType.BY_XPATH, + classes=["class1"], + other_attributes={"name": "some_name"}, + ) + target_node = Node( + classes=["class2", "class3"], other_attributes={"src": "img.png"} + ) + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() + + +def test_imitate_by_xpath_invalid_target(): + user_selector = Selector( + selector_type=SelectorType.BY_XPATH, + tag="img", + other_attributes={"name": "some_name"}, + ) + target_node = Node(other_attributes={"name": "some_name"}) + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_unimplemented.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_unimplemented.py new file mode 100644 index 0000000..067aada --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_unimplemented.py @@ -0,0 +1,16 @@ +import pytest + +from src.node import Node +from src.selector import Selector +from src.selector_imitator import SelectorImitator, ImitationError + + +def test_imitate_unimplemented(): + user_selector = Selector( + selector_type=42, + tag="img", + other_attributes={"name": "some_name"}, + ) + target_node = Node(other_attributes={"name": "some_name"}) + with pytest.raises(ImitationError): + SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_integration.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_integration.py new file mode 100644 index 0000000..8cafefe --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_integration.py @@ -0,0 +1,86 @@ +from src.node import Node +from src.selector import Selector +from src.selector_imitator import SelectorImitator + + +def test_integration_css_selector_name(): + user_selector = Selector.from_css("div[name='old_name']") + target_node = Node( + tag="div", + id="my_div", + classes=["cls1", "class2"], + index=1, + other_attributes={"name": "new_name", "href": "some_link"}, + inner_text="hello world", + ) + assert ( + str(SelectorImitator(user_selector, target_node).imitate()[0]) + == "div[name='new_name']" + ) + + +def test_integration_css_selector_tag(): + user_selector = Selector.from_css("h1.cls1[name='some_name']") + target_node = Node( + tag="h2", + id="my_div", + classes=["cls1", "class2"], + index=1, + other_attributes={"name": "some_name", "href": "some_link"}, + inner_text="hello world", + ) + assert ( + str(SelectorImitator(user_selector, target_node).imitate()[0]) + == "h2.cls1[name='some_name']" + ) + + +def test_integration_xpath_selector_value(): + user_selector = Selector.from_xpath("//*[@value='Log In']") + target_node = Node( + tag="input", + classes=["fadeIn", "fourth"], + other_attributes={ + "_ngcontent-wvw-c3": "", + "type": "button", + "value": "Log In New", + }, + ) + assert ( + str(SelectorImitator(user_selector, target_node).imitate()[0]) + == "//*[@value='Log In New']" + ) + + +def test_integration_xpath_selector_class_split(): + user_selector = Selector.from_xpath("//*[@class='fadeIn'][@value='Log In']") + target_node = Node( + tag="input", + classes=["fadeIn", "fourth"], + other_attributes={ + "_ngcontent-wvw-c3": "", + "type": "button", + "value": "Log In New", + }, + ) + assert ( + str(SelectorImitator(user_selector, target_node).imitate()[0]) + == "//*[contains(@class, 'fadeIn')][@value='Log In New']" + ) + + +def test_integration_xpath_selector_class_no_split(): + user_selector = Selector.from_xpath("//*[@class='fadeIn fourth'][@value='Log In']") + target_node = Node( + tag="input", + classes=["fadeIn", "fourth"], + other_attributes={ + "_ngcontent-wvw-c3": "", + "type": "button", + "value": "Log In New", + }, + ) + assert ( + str(SelectorImitator(user_selector, target_node).imitate()[0]) + == "//*[@class='fadeIn fourth'][@value='Log In New']" + ) diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_css_parser.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_css_parser.py new file mode 100644 index 0000000..30108a4 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_css_parser.py @@ -0,0 +1,66 @@ +import pytest + +from src.selector_parser import CSSSelectorParser, ParsingError + + +def test_validation_success_simple(): + CSSSelectorParser("p") + + +def test_validation_success_complex(): + CSSSelectorParser("div#hello.class_name[href='hello world']") + + +def test_validation_error(): + with pytest.raises(ParsingError): + CSSSelectorParser("div#hello_world span.some_class") + + +def test_parse_tag(): + selector = "div#hello.class_name[href='hello world']" + assert CSSSelectorParser(selector).get_tag() == "div" + + +def test_parse_no_tag(): + selector = "#hello.class_name[href='hello world']" + assert CSSSelectorParser(selector).get_tag() == "" + + +def test_parse_tag_simple(): + selector = "div" + assert CSSSelectorParser(selector).get_tag() == "div" + + +def test_parse_id(): + selector = "div#hello-world.class_name[href='hello world']" + assert CSSSelectorParser(selector).get_id() == "hello-world" + + +def test_parse_id_empty(): + selector = "div.class_name[href='hello #world']" + assert CSSSelectorParser(selector).get_id() == "" + + +def test_parse_classes(): + selector = "div#hello.class_name.class_2[href='hello world']" + assert set(CSSSelectorParser(selector).get_classes()) == {"class_name", "class_2"} + + +def test_parse_classes_empty(): + selector = "div#hello[href='hello.world']" + assert set(CSSSelectorParser(selector).get_classes()) == set() + + +def test_parse_attributes_single_quotes(): + selector = "div#hello[href='hello.world']" + assert CSSSelectorParser(selector).get_attributes() == {"href": "hello.world"} + + +def test_parse_attributes_double_quotes(): + selector = 'div.class_hello[name="hello"]' + assert CSSSelectorParser(selector).get_attributes() == {"name": "hello"} + + +def test_parse_attributes_empty(): + selector = "div.class_hello" + assert CSSSelectorParser(selector).get_attributes() == {} diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_xpath_parser.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_xpath_parser.py new file mode 100644 index 0000000..199c7ad --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_xpath_parser.py @@ -0,0 +1,98 @@ +import pytest + +from src.selector_parser import XPathParser, ParsingError + + +def test_validation_success_simple(): + XPathParser("//p") + + +def test_validation_success_complex(): + XPathParser("//label[@id='message23']") + + +def test_validation_success_no_tag(): + XPathParser("//*[@class='cls1'][1]") + + +def test_validation_error(): + with pytest.raises(ParsingError): + XPathParser("//*[@type='text']//following::input") + + +def test_parse_tag(): + assert XPathParser("//label[@id='message23']").get_tag() == "label" + + +def test_parse_tag_simple(): + assert XPathParser("//h2").get_tag() == "h2" + + +def test_parse_no_tag(): + assert XPathParser("//*[@class='cls1'][1]").get_tag() == "" + + +def test_parse_id(): + assert XPathParser("//*[@id='rt-feature']").get_id() == "rt-feature" + + +def test_parse_no_id(): + assert XPathParser("//*[@class='cls1'][1]").get_id() == "" + + +def test_parse_classes_single_class(): + assert XPathParser("//*[@class='cls1'][1]").get_classes() == ["cls1"] + + +def test_parse_classes_multiple_classes(): + assert XPathParser("//*[@class='cls1 cls2'][1]").get_classes() == ["cls1", "cls2"] + + +def test_parse_classes_single_class_with_contains(): + assert XPathParser("//*[contains(@class,'btn')]").get_classes() == ["btn"] + + +def test_parse_classes_multiple_classes_with_contains(): + assert XPathParser("//*[contains(@class,'btn cls1')]").get_classes() == [ + "btn", + "cls1", + ] + + +def test_parse_classes_no_class(): + assert XPathParser("//label[@id='message23']").get_classes() == [] + + +def test_parse_attributes_single_quotes(): + selector = "//div[@id='hello'][@href='hello.world']" + assert XPathParser(selector).get_attributes() == {"href": "hello.world"} + + +def test_parse_attributes_double_quotes(): + selector = '//*[@class="class-hello" and @name="hello"]' + assert XPathParser(selector).get_attributes() == {"name": "hello"} + + +def test_parse_attributes_empty(): + selector = "//*[@class='class-hello']" + assert XPathParser(selector).get_attributes() == {} + + +def test_parse_index(): + selector = "//*[@class='cls1 cls2'][2]" + assert XPathParser(selector).get_index() == 2 + + +def test_parse_index_no_index(): + selector = "//div[@id='hello'][@href='hello.world']" + assert XPathParser(selector).get_index() is None + + +def test_parse_inner_text(): + selector = "//p[@class='cls1 cls2' and text()='Hello, World!'][2]" + assert XPathParser(selector).get_inner_text() == "Hello, World!" + + +def test_parse_inner_text_empty(): + selector = "//p[@class='cls1 cls2'][2]" + assert XPathParser(selector).get_inner_text() == "" diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_from_string.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_from_string.py new file mode 100644 index 0000000..976e13b --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_from_string.py @@ -0,0 +1,81 @@ +from src.selector import Selector, SelectorType + + +def test_from_class_name(): + assert Selector.from_class_name("cls") == Selector( + selector_type=SelectorType.BY_CLASS_NAME, classes=["cls"] + ) + + +def test_from_css_simple(): + css_selector = "div" + assert Selector.from_css(css_selector) == Selector( + selector_type=SelectorType.BY_CSS_SELECTOR, tag="div" + ) + + +def test_from_css_complex(): + css_selector = "div#hello.class_name.cls2[href='hello world']" + assert Selector.from_css(css_selector) == Selector( + selector_type=SelectorType.BY_CSS_SELECTOR, + tag="div", + id="hello", + classes=["class_name", "cls2"], + other_attributes={"href": "hello world"}, + ) + + +def test_from_id(): + assert Selector.from_id("hello") == Selector( + selector_type=SelectorType.BY_ID, id="hello" + ) + + +def test_from_link_text(): + assert Selector.from_link_text("hello_world") == Selector( + selector_type=SelectorType.BY_LINK_TEXT, inner_text="hello_world" + ) + + +def test_from_name(): + assert Selector.from_name("some_name") == Selector( + selector_type=SelectorType.BY_NAME, other_attributes={"name": "some_name"} + ) + + +def test_from_partial_link_text(): + assert Selector.from_partial_link_text("hello_world") == Selector( + selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, inner_text="hello_world" + ) + + +def test_from_tag_name(): + assert Selector.from_tag_name("h3") == Selector( + selector_type=SelectorType.BY_TAG_NAME, tag="h3" + ) + + +def test_from_xpath_simple(): + xpath_selector = "//div" + assert Selector.from_xpath(xpath_selector) == Selector( + selector_type=SelectorType.BY_XPATH, tag="div" + ) + + +def test_from_xpath_complex(): + xpath_selector = ( + "//div[@name='my_selector'][@class='classname cls2' and text()='hello world']" + ) + assert Selector.from_xpath(xpath_selector) == Selector( + selector_type=SelectorType.BY_XPATH, + tag="div", + classes=["classname", "cls2"], + other_attributes={"name": "my_selector"}, + inner_text="hello world", + ) + + +def test_from_type_and_value(): + assert Selector.from_type_and_value( + SelectorType.BY_ID, value="some-id" + ) == Selector(selector_type=SelectorType.BY_ID, id="some-id") diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_to_string.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_to_string.py new file mode 100644 index 0000000..0e130c2 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_to_string.py @@ -0,0 +1,83 @@ +import pytest + +from src.selector import Selector, SelectorType + + +def test_class_name_selector_to_string(): + assert ( + str(Selector(selector_type=SelectorType.BY_CLASS_NAME, classes=["clsname"])) + == "clsname" + ) + + +def test_class_name_selector_to_string_many_classes(): + with pytest.raises(ValueError): + str( + Selector(selector_type=SelectorType.BY_CLASS_NAME, classes=["cls1", "cls2"]) + ) + + +def test_class_name_selector_to_string_no_class(): + with pytest.raises(ValueError): + str(Selector(selector_type=SelectorType.BY_CLASS_NAME)) + + +def test_css_selector_to_string(): + assert ( + str(Selector(selector_type=SelectorType.BY_CSS_SELECTOR, tag="h2", id="hello")) + == "h2#hello" + ) + + +def test_id_selector_to_string(): + assert str(Selector(selector_type=SelectorType.BY_ID, id="hello")) == "hello" + + +def test_link_text_selector_to_string(): + assert ( + str(Selector(selector_type=SelectorType.BY_LINK_TEXT, inner_text="hello world")) + == "hello world" + ) + + +def test_name_selector_to_string(): + assert ( + str( + Selector( + selector_type=SelectorType.BY_NAME, other_attributes={"name": "hello"} + ) + ) + == "hello" + ) + + +def test_name_selector_to_string_no_name(): + with pytest.raises(ValueError): + str( + Selector( + selector_type=SelectorType.BY_NAME, other_attributes={"value": "hello"} + ) + ) + + +def test_partial_link_text_selector_to_string(): + assert ( + str( + Selector( + selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, + inner_text="hello world", + ) + ) + == "hello world" + ) + + +def test_tag_selector_to_string(): + assert str(Selector(selector_type=SelectorType.BY_TAG_NAME, tag="div")) == "div" + + +def test_xpath_selector_to_string(): + assert ( + str(Selector(selector_type=SelectorType.BY_XPATH, tag="h2", id="hello")) + == "//h2[@id='hello']" + ) diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_css_selector_constructor.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_css_selector_constructor.py new file mode 100644 index 0000000..5885090 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_css_selector_constructor.py @@ -0,0 +1,40 @@ +from src.selector_to_string import CSSSelectorConstructor + + +def test_css_constructor_only_tag(): + assert CSSSelectorConstructor(tag="h2").get_string_representation() == "h2" + + +def test_css_constructor_only_id(): + assert ( + CSSSelectorConstructor(element_id="hello").get_string_representation() + == "#hello" + ) + + +def test_css_constructor_id_with_tag(): + assert ( + CSSSelectorConstructor(tag="h2", element_id="hello").get_string_representation() + == "h2#hello" + ) + + +def test_css_constructor_id_with_tag_and_classes(): + assert ( + CSSSelectorConstructor( + tag="h2", element_id="hello", classes=["class1", "cls2"] + ).get_string_representation() + == "h2#hello.class1.cls2" + ) + + +def test_css_constructor_all_elements(): + assert ( + CSSSelectorConstructor( + tag="h2", + element_id="hello", + classes=["class1", "cls2"], + other_attributes={"href": "hello world"}, + ).get_string_representation() + == "h2#hello.class1.cls2[href='hello world']" + ) diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_xpath_constructor.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_xpath_constructor.py new file mode 100644 index 0000000..37ded56 --- /dev/null +++ b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_xpath_constructor.py @@ -0,0 +1,52 @@ +from src.selector_to_string import XPathConstructor + + +def test_xpath_constructor_only_tag(): + assert XPathConstructor(tag="h2").get_string_representation() == "//h2" + + +def test_xpath_constructor_only_id(): + assert ( + XPathConstructor(element_id="hello").get_string_representation() + == "//*[@id='hello']" + ) + + +def test_xpath_constructor_id_with_tag(): + assert ( + XPathConstructor(tag="h2", element_id="hello").get_string_representation() + == "//h2[@id='hello']" + ) + + +def test_xpath_constructor_id_with_tag_and_classes(): + assert ( + XPathConstructor( + tag="h2", element_id="hello", classes=["class1", "cls2"] + ).get_string_representation() + == "//h2[@id='hello'][@class='class1 cls2']" + ) + + +def test_xpath_constructor_id_with_tag_and_classes_split(): + assert ( + XPathConstructor( + tag="h2", element_id="hello", classes=["class1", "cls2"] + ).get_string_representation(split_classes=True) + == "//h2[@id='hello'][contains(@class, 'class1')][contains(@class, 'cls2')]" + ) + + +def test_xpath_constructor_all_elements(): + assert ( + XPathConstructor( + tag="h2", + element_id="hello", + classes=["cls1"], + other_attributes={"value": "42"}, + index=11, + inner_text="Hello, World!", + ).get_string_representation() + == "//h2[@id='hello'][@class='cls1']" + "[@value='42'][text()='Hello, World!'][11]" + ) 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 From 2d3f6c73da3a852f6507c5dc62683f5bf73a52ab Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Thu, 14 Sep 2023 19:47:09 +0300 Subject: [PATCH 19/24] remove imitator source --- .../healenium-selector-imitator/.coveragerc | 6 - .../web/healenium-selector-imitator/.flake8 | 8 - .../.github/workflows/python-package.yml | 37 ---- .../healenium-selector-imitator/.gitignore | 6 - .../healenium-selector-imitator/Dockerfile | 8 - .../web/healenium-selector-imitator/README.md | 70 -------- .../web/healenium-selector-imitator/app.py | 55 ------ .../docker-compose.yml | 7 - .../web/healenium-selector-imitator/mypy.ini | 3 - .../requirements.txt | 2 - .../requirements_dev.txt | 9 - .../src/__init__.py | 0 .../src/datamodel/__init__.py | 5 - .../src/datamodel/imitation_request.py | 13 -- .../src/datamodel/imitation_response.py | 10 -- .../healenium-selector-imitator/src/node.py | 20 --- .../src/selector.py | 158 ------------------ .../src/selector_imitator.py | 150 ----------------- .../src/selector_parser.py | 132 --------------- .../src/selector_to_string.py | 79 --------- .../test/__init__.py | 0 .../test/test_api.py | 114 ------------- .../test/test_imitate/__init__.py | 0 .../test_imitate_by_class_name.py | 40 ----- .../test_imitate_by_css_selector.py | 46 ----- .../test/test_imitate/test_imitate_by_id.py | 21 --- .../test_imitate/test_imitate_by_link_text.py | 30 ---- .../test/test_imitate/test_imitate_by_name.py | 34 ---- .../test_imitate_by_partial_link_text.py | 37 ---- .../test_imitate/test_imitate_by_tag_name.py | 21 --- .../test_imitate/test_imitate_by_xpath.py | 46 ----- .../test_imitate_unimplemented.py | 16 -- .../test/test_integration.py | 86 ---------- .../test/test_parser/__init__.py | 0 .../test/test_parser/test_css_parser.py | 66 -------- .../test/test_parser/test_xpath_parser.py | 98 ----------- .../test/test_selector/__init__.py | 0 .../test_selector_from_string.py | 81 --------- .../test_selector/test_selector_to_string.py | 83 --------- .../test/test_selector_to_string/__init__.py | 0 .../test_css_selector_constructor.py | 40 ----- .../test_xpath_constructor.py | 52 ------ 42 files changed, 1689 deletions(-) delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/.coveragerc delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/.flake8 delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/.github/workflows/python-package.yml delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/.gitignore delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/Dockerfile delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/README.md delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/app.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/docker-compose.yml delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/mypy.ini delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/requirements.txt delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/requirements_dev.txt delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/__init__.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/__init__.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_request.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_response.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/node.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/selector.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/selector_imitator.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/selector_parser.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/src/selector_to_string.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/__init__.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_api.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/__init__.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_class_name.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_css_selector.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_id.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_link_text.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_name.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_partial_link_text.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_tag_name.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_xpath.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_unimplemented.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_integration.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/__init__.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_css_parser.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_xpath_parser.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/__init__.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_from_string.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_to_string.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/__init__.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_css_selector_constructor.py delete mode 100644 healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_xpath_constructor.py diff --git a/healenium/shell-installation/web/healenium-selector-imitator/.coveragerc b/healenium/shell-installation/web/healenium-selector-imitator/.coveragerc deleted file mode 100644 index 521e972..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/.coveragerc +++ /dev/null @@ -1,6 +0,0 @@ -# .coveragerc to control coverage.py -[run] -omit = - */site-packages/* - */distutils/* - tests/* \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/.flake8 b/healenium/shell-installation/web/healenium-selector-imitator/.flake8 deleted file mode 100644 index 2aa8cb4..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/.flake8 +++ /dev/null @@ -1,8 +0,0 @@ -[flake8] -max-line-length = 88 -exclude = - .git - .idea - .pytest_cache - env - dist \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/.github/workflows/python-package.yml b/healenium/shell-installation/web/healenium-selector-imitator/.github/workflows/python-package.yml deleted file mode 100644 index e4d0f13..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/.github/workflows/python-package.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Python package - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.7 - uses: actions/setup-python@v2 - with: - python-version: '3.7' - - name: Install dependencies - run: | - pip install -r requirements_dev.txt - - name: Check types with mypy - run: | - mypy src app.py - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Lint with black - run: | - black --check . - - name: Test with pytest - run: | - pytest diff --git a/healenium/shell-installation/web/healenium-selector-imitator/.gitignore b/healenium/shell-installation/web/healenium-selector-imitator/.gitignore deleted file mode 100644 index 2149682..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -env -.idea -__pycache__ -.coverage -htmlcov -dist \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/Dockerfile b/healenium/shell-installation/web/healenium-selector-imitator/Dockerfile deleted file mode 100644 index b160254..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM python:3.7-slim-stretch - -COPY ./requirements.txt ./requirements.txt -COPY ./dist ./ - -RUN pip install -r requirements.txt - -CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/README.md b/healenium/shell-installation/web/healenium-selector-imitator/README.md deleted file mode 100644 index 71f2c1f..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# Healenium selector imitator - -Selector imitator tries to reconstruct a user selector, changing only fields that the user modified in HTML. It works with the original selector (and its type) and target node (so it should be applied after the best node is already found). It proposes possible healed selectors or raises an error. -Proposed selectors are not guaranteed to find a unique web element. Uniqueness must be checked outside of the service with a selenium driver. - -1. [Example request and response](#example) -2. [Image and container resources consumption](#resources) -3. [Installation with Docker](#installation) -4. [Creating your own image from Dockerfile](#image) -5. [Local testing](#testing) - -### Example request and response - -Here is an example request. You can try out different requests with Swagger after the [installation](#installation). -![image](https://user-images.githubusercontent.com/40484210/127833016-10da747f-ae4d-480f-9624-ec1266cbbb25.png) -![image](https://user-images.githubusercontent.com/40484210/127833088-59eeced9-17c3-4b60-b1ee-f97d4421ff33.png) - - -### Image and container resources consumption -![image](https://user-images.githubusercontent.com/40484210/123598005-b7c7ff00-d7fc-11eb-9be6-fa20c181bb47.png) -![image](https://user-images.githubusercontent.com/40484210/123598058-c3b3c100-d7fc-11eb-85d9-380bacd53d6a.png) - - -### Installation with Docker -Run the following command to install and use Healenium selector imitator as a stand-alone service (you'll need docker installed): -``` -docker compose up -``` -Now you can access an API at http://localhost:8000/ -Check http://localhost:8000/docs for Swagger documentation. - -### Creating your own image from Dockerfile -If you wish to make some changes to the code and test them in Docker environment, you will need to create an image. -Run these commands from the repository directory, change the version if needed (you'll need docker and pyarmor installed): -``` -pyarmor obfuscate --platform linux.x86_64.7 --recursive --output dist/src src/__init__.py -pyarmor obfuscate --platform linux.x86_64.7 --exact app.py -docker build -t healenium/hlm-selector-imitator:1 . -docker run -d -p 8000:8000 healenium/hlm-selector-imitator:1 -``` - -### Local testing -To test or lint locally, create a virtual environment with Pyhton 3.7 and install packages from requirements_dev.txt - -Test with [pytest](https://docs.pytest.org/en/6.2.x/): -``` -pytest -``` - -Get [coverage](https://coverage.readthedocs.io/en/coverage-5.5/#) report: -``` -coverage run -m pytest -coverage report -m -coverage html -``` - -Check types with [mypy](https://mypy.readthedocs.io/en/stable/): -``` -mypy src app.py -``` - -Lint with [flake8](https://flake8.pycqa.org/en/latest/): -``` -flake8 -``` - -Format code with [black](https://github.com/psf/black): -``` -black . -``` diff --git a/healenium/shell-installation/web/healenium-selector-imitator/app.py b/healenium/shell-installation/web/healenium-selector-imitator/app.py deleted file mode 100644 index f08a81d..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/app.py +++ /dev/null @@ -1,55 +0,0 @@ -import os -import uvicorn - -from fastapi import FastAPI, Request -from fastapi.responses import JSONResponse -from src.datamodel import ImitationRequestModel, ImitationResponseModel -from src.selector import Selector -from src.selector_imitator import SelectorImitator, ImitationError -from src.selector_parser import ParsingError -from typing import List - - -app = FastAPI() - - -@app.exception_handler(ImitationError) -async def imitation_error_handler( - request: Request, exc: ImitationError -) -> JSONResponse: - return JSONResponse( - status_code=422, - content={"detail": [{"msg": f"Unable to imitate the user selector: {exc}"}]}, - ) - - -@app.exception_handler(ParsingError) -async def parsing_error_handler(request: Request, exc: ParsingError) -> JSONResponse: - return JSONResponse( - status_code=422, - content={"detail": [{"msg": f"Unable to parse the user selector: {exc}"}]}, - ) - - -@app.get("/") -def main() -> str: - return "this is an entry point of the selector imitator" - - -@app.post("/imitate", response_model=List[ImitationResponseModel]) -async def imitate(request: ImitationRequestModel) -> List[ImitationResponseModel]: - user_selector = Selector.from_type_and_value( - selector_type=request.user_selector.type, value=request.user_selector.value - ) - imitator = SelectorImitator(user_selector, request.target_node) - result = [ - ImitationResponseModel( - selector_type=selector.selector_type, selector_value=str(selector) - ) - for selector in imitator.imitate() - ] - return result - - -if __name__ == "__main__": - uvicorn.run("app:app", host="0.0.0.0", port=os.getenv("PORT", 8000)) diff --git a/healenium/shell-installation/web/healenium-selector-imitator/docker-compose.yml b/healenium/shell-installation/web/healenium-selector-imitator/docker-compose.yml deleted file mode 100644 index 0a8b649..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/docker-compose.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: "3.9" -services: - selector-imitator: - image: "healenium/hlm-selector-imitator:1" - restart: on-failure - ports: - - "8000:8000" diff --git a/healenium/shell-installation/web/healenium-selector-imitator/mypy.ini b/healenium/shell-installation/web/healenium-selector-imitator/mypy.ini deleted file mode 100644 index 3e81927..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/mypy.ini +++ /dev/null @@ -1,3 +0,0 @@ -[mypy] -ignore_missing_imports = True -strict = True \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/requirements.txt b/healenium/shell-installation/web/healenium-selector-imitator/requirements.txt deleted file mode 100644 index f185c39..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -fastapi==0.65.2 -uvicorn==0.13.4 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/requirements_dev.txt b/healenium/shell-installation/web/healenium-selector-imitator/requirements_dev.txt deleted file mode 100644 index 21f3a76..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/requirements_dev.txt +++ /dev/null @@ -1,9 +0,0 @@ -black==21.6b0 -coverage==5.5 -fastapi==0.65.2 -flake8==3.9.2 -mypy==0.910 -pyarmor==6.7.3 -pytest==6.2.4 -requests==2.25.1 -uvicorn==0.13.4 \ No newline at end of file diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/__init__.py deleted file mode 100644 index b689ec3..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .imitation_request import ImitationRequestModel -from .imitation_response import ImitationResponseModel - - -__all__ = ["ImitationRequestModel", "ImitationResponseModel"] diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_request.py b/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_request.py deleted file mode 100644 index 01a24bd..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_request.py +++ /dev/null @@ -1,13 +0,0 @@ -from pydantic import BaseModel, Field -from src.node import Node -from src.selector import SelectorType - - -class UserSelector(BaseModel): - type: SelectorType - value: str - - -class ImitationRequestModel(BaseModel): - user_selector: UserSelector = Field(..., alias="userSelector") - target_node: Node = Field(..., alias="targetNode") diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_response.py b/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_response.py deleted file mode 100644 index f36a01b..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/src/datamodel/imitation_response.py +++ /dev/null @@ -1,10 +0,0 @@ -from pydantic import BaseModel, Field -from src.selector import SelectorType - - -class ImitationResponseModel(BaseModel): - selector_type: SelectorType = Field(..., alias="type") - selector_value: str = Field(..., alias="value") - - class Config: - allow_population_by_field_name = True diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/node.py b/healenium/shell-installation/web/healenium-selector-imitator/src/node.py deleted file mode 100644 index b25883b..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/src/node.py +++ /dev/null @@ -1,20 +0,0 @@ -from pydantic import BaseModel, Field, validator -from typing import Optional, List, Dict, Union - - -class Node(BaseModel): - tag: str = "" - id: str = "" - classes: List[str] = Field(default_factory=list) - index: Optional[int] = None - other_attributes: Dict[str, str] = Field(default_factory=dict, alias="other") - inner_text: str = Field("", alias="innerText") - - class Config: - allow_population_by_field_name = True - - @validator("classes", pre=True) - def split_classes(cls, value: Union[str, List[str]]) -> List[str]: - if isinstance(value, str): - return value.split() - return value diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/selector.py b/healenium/shell-installation/web/healenium-selector-imitator/src/selector.py deleted file mode 100644 index 29cfcfa..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/src/selector.py +++ /dev/null @@ -1,158 +0,0 @@ -from dataclasses import dataclass -from enum import Enum -from .selector_parser import CSSSelectorParser, XPathParser -from .selector_to_string import CSSSelectorConstructor, XPathConstructor -from typing import Optional, List, Dict - - -class SelectorType(str, Enum): - BY_CLASS_NAME = "By.className" - BY_CSS_SELECTOR = "By.cssSelector" - BY_ID = "By.id" - BY_LINK_TEXT = "By.linkText" - BY_NAME = "By.name" - BY_PARTIAL_LINK_TEXT = "By.partialLinkText" - BY_TAG_NAME = "By.tagName" - BY_XPATH = "By.xpath" - - -@dataclass -class Selector: - selector_type: SelectorType - tag: Optional[str] = None - id: Optional[str] = None - classes: Optional[List[str]] = None - index: Optional[int] = None - other_attributes: Optional[Dict[str, str]] = None - inner_text: Optional[str] = None - split_classes: bool = False - - @classmethod - def from_type_and_value(cls, selector_type: SelectorType, value: str) -> "Selector": - if selector_type is SelectorType.BY_CLASS_NAME: - return cls.from_class_name(value) - elif selector_type is SelectorType.BY_CSS_SELECTOR: - return cls.from_css(value) - elif selector_type is SelectorType.BY_ID: - return cls.from_id(value) - elif selector_type is SelectorType.BY_LINK_TEXT: - return cls.from_link_text(value) - elif selector_type is SelectorType.BY_NAME: - return cls.from_name(value) - elif selector_type is SelectorType.BY_PARTIAL_LINK_TEXT: - return cls.from_partial_link_text(value) - elif selector_type is SelectorType.BY_TAG_NAME: - return cls.from_tag_name(value) - elif selector_type is SelectorType.BY_XPATH: - return cls.from_xpath(value) - else: - raise ValueError(f"Invalid selector type: {selector_type}") - - @classmethod - def from_class_name(cls, class_name: str) -> "Selector": - return cls(selector_type=SelectorType.BY_CLASS_NAME, classes=[class_name]) - - @classmethod - def from_css(cls, css_selector: str) -> "Selector": - parser = CSSSelectorParser(css_selector) - return cls( - selector_type=SelectorType.BY_CSS_SELECTOR, - tag=parser.get_tag() or None, - id=parser.get_id() or None, - classes=parser.get_classes() or None, - other_attributes=parser.get_attributes() or None, - ) - - @classmethod - def from_id(cls, element_id: str) -> "Selector": - return cls(selector_type=SelectorType.BY_ID, id=element_id) - - @classmethod - def from_link_text(cls, link_text: str) -> "Selector": - return cls(selector_type=SelectorType.BY_LINK_TEXT, inner_text=link_text) - - @classmethod - def from_name(cls, name: str) -> "Selector": - return cls(selector_type=SelectorType.BY_NAME, other_attributes={"name": name}) - - @classmethod - def from_partial_link_text(cls, partial_link_text: str) -> "Selector": - return cls( - selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, - inner_text=partial_link_text, - ) - - @classmethod - def from_tag_name(cls, tag_name: str) -> "Selector": - return cls(selector_type=SelectorType.BY_TAG_NAME, tag=tag_name) - - @classmethod - def from_xpath(cls, xpath_selector: str) -> "Selector": - parser = XPathParser(xpath_selector) - return cls( - selector_type=SelectorType.BY_XPATH, - tag=parser.get_tag() or None, - id=parser.get_id() or None, - classes=parser.get_classes() or None, - index=parser.get_index(), - other_attributes=parser.get_attributes() or None, - inner_text=parser.get_inner_text() or None, - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Selector): - return False - return ( - self.selector_type == other.selector_type - and self.tag == other.tag - and self.id == other.id - and set(self.classes or []) == set(other.classes or []) - and self.index == other.index - and self.other_attributes == other.other_attributes - and self.inner_text == other.inner_text - ) - - def __str__(self) -> str: - if self.selector_type is SelectorType.BY_CLASS_NAME: - if self.classes is None or len(self.classes) == 0: - raise ValueError( - "BY_CLASS_NAME selector must contain one class name, none provided." - ) - if len(self.classes) == 1: - return self.classes[0] - else: - raise ValueError( - "Ambiguous BY_CLASS_NAME selector. " - "Only one class allowed for this selector type." - ) - elif self.selector_type is SelectorType.BY_CSS_SELECTOR: - return CSSSelectorConstructor( - tag=self.tag, - element_id=self.id, - classes=self.classes, - other_attributes=self.other_attributes, - ).get_string_representation() - elif self.selector_type is SelectorType.BY_ID: - return self.id if self.id is not None else "" - elif self.selector_type is SelectorType.BY_LINK_TEXT: - return self.inner_text if self.inner_text is not None else "" - elif self.selector_type is SelectorType.BY_NAME: - if self.other_attributes is not None and "name" in self.other_attributes: - return self.other_attributes["name"] - else: - raise ValueError("BY_NAME selector must contain name attribute.") - elif self.selector_type is SelectorType.BY_PARTIAL_LINK_TEXT: - return self.inner_text if self.inner_text is not None else "" - elif self.selector_type is SelectorType.BY_TAG_NAME: - return self.tag if self.tag is not None else "" - elif self.selector_type is SelectorType.BY_XPATH: - return XPathConstructor( - tag=self.tag, - element_id=self.id, - classes=self.classes, - other_attributes=self.other_attributes, - index=self.index, - inner_text=self.inner_text, - ).get_string_representation(split_classes=self.split_classes) - else: - return "" diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/selector_imitator.py b/healenium/shell-installation/web/healenium-selector-imitator/src/selector_imitator.py deleted file mode 100644 index ebfa4f9..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/src/selector_imitator.py +++ /dev/null @@ -1,150 +0,0 @@ -from .node import Node -from .selector import Selector, SelectorType -from typing import List - - -class ImitationError(Exception): - pass - - -class SelectorImitator: - def __init__(self, user_selector: Selector, target_node: Node): - self.user_selector = user_selector - self.target_node = target_node - - def _imitate_class_name(self) -> List[Selector]: - if self.target_node.classes: - return [ - Selector( - selector_type=SelectorType.BY_CLASS_NAME, - classes=[target_class], - ) - for target_class in self.target_node.classes - ] - else: - raise ImitationError("Target node does not belong to any class.") - - def _imitate_css_or_xpath(self) -> Selector: - target_selector = Selector(selector_type=self.user_selector.selector_type) - if self.user_selector.tag is not None: - if self.target_node.tag: - target_selector.tag = self.target_node.tag - else: - raise ImitationError("Target node does not have any tag.") - if self.user_selector.id is not None: - if self.target_node.id: - target_selector.id = self.target_node.id - else: - raise ImitationError("Target node does not have any id.") - if self.user_selector.classes is not None: - if self.target_node.classes: - target_selector.classes = [] - some_class_changed = False - for cls in self.user_selector.classes: - if cls in self.target_node.classes: - target_selector.classes.append(cls) - else: - some_class_changed = True - break - if some_class_changed: - target_selector.classes = self.target_node.classes - else: - raise ImitationError("Target node does not belong to any classes.") - target_selector.split_classes = ( - target_selector.classes != self.target_node.classes - ) - if self.user_selector.index is not None: - if self.target_node.index: - target_selector.index = self.target_node.index - else: - raise ImitationError("Target node does not have any index.") - if self.user_selector.inner_text is not None: - if self.target_node.inner_text: - target_selector.inner_text = self.target_node.inner_text - else: - raise ImitationError("Target node does not have any inner text.") - if self.user_selector.other_attributes is not None: - target_selector.other_attributes = {} - for attribute in self.user_selector.other_attributes: - if attribute in self.target_node.other_attributes: - target_selector.other_attributes[ - attribute - ] = self.target_node.other_attributes[attribute] - else: - raise ImitationError( - f"Target node does not have an attribute {attribute}." - ) - return target_selector - - def _imitate_id(self) -> Selector: - if self.target_node.id: - return Selector(selector_type=SelectorType.BY_ID, id=self.target_node.id) - else: - raise ImitationError("Target node does not have an id.") - - def _imitate_link_text(self) -> Selector: - if self.target_node.tag != "a": - raise ImitationError( - "Target node is not an anchor tag, " - "so selector by link text is not applicable." - ) - if self.target_node.inner_text: - return Selector( - selector_type=self.user_selector.selector_type, - inner_text=self.target_node.inner_text, - ) - else: - raise ImitationError("Target node does not have a link text.") - - def _imitate_name(self) -> Selector: - if "name" in self.target_node.other_attributes: - if ( - self.user_selector.other_attributes is not None - and "name" in self.user_selector.other_attributes - ): - return Selector( - selector_type=SelectorType.BY_NAME, - other_attributes={ - "name": self.target_node.other_attributes["name"] - }, - ) - else: - raise ImitationError( - "Invalid user selector: does not contain name attribute, " - "while type is BY_NAME." - ) - else: - raise ImitationError("Target node does not have a name attribute.") - - def _by_tag_name(self) -> Selector: - if self.target_node.tag: - return Selector( - selector_type=SelectorType.BY_TAG_NAME, tag=self.target_node.tag - ) - else: - raise ImitationError("Target node does not have a tag name.") - - def imitate(self) -> List[Selector]: - """Return a list of possible selectors for a target node that imitates a user selector. - Raise ImitationError if the target node cannot be imitated. - """ - if self.user_selector.selector_type is SelectorType.BY_CLASS_NAME: - return self._imitate_class_name() - elif self.user_selector.selector_type in [ - SelectorType.BY_CSS_SELECTOR, - SelectorType.BY_XPATH, - ]: - return [self._imitate_css_or_xpath()] - elif self.user_selector.selector_type is SelectorType.BY_ID: - return [self._imitate_id()] - elif self.user_selector.selector_type in [ - SelectorType.BY_LINK_TEXT, - SelectorType.BY_PARTIAL_LINK_TEXT, - ]: - return [self._imitate_link_text()] - elif self.user_selector.selector_type is SelectorType.BY_NAME: - return [self._imitate_name()] - elif self.user_selector.selector_type is SelectorType.BY_TAG_NAME: - return [self._by_tag_name()] - else: - raise ImitationError("Imitation for user selector type is not implemented.") diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/selector_parser.py b/healenium/shell-installation/web/healenium-selector-imitator/src/selector_parser.py deleted file mode 100644 index dea3347..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/src/selector_parser.py +++ /dev/null @@ -1,132 +0,0 @@ -import re - -from typing import List, Dict, Optional - - -class ParsingError(Exception): - pass - - -class ParsingUtils: - @staticmethod - def remove_quoted_text(text: str) -> str: - result = text - single_quote_expression = re.compile("'.*'") - double_quote_expression = re.compile('".*"') - for expression in [single_quote_expression, double_quote_expression]: - while True: - search_result = expression.search(result) - if search_result is not None: - idx_from, idx_to = search_result.span() - result = result[:idx_from] + result[idx_to:] - else: - break - return result - - -class CSSSelectorParser: - def __init__(self, selector: str): - self.selector = selector - self.validate() - - def validate(self) -> None: - expression = re.compile(r"^([\w-]*)(\.[\w-]+|#[\w-]+|\[.+])*$") - if expression.match(self.selector) is None: - raise ParsingError("Cannot parse CSS selector.") - - def get_tag(self) -> str: - expression = re.compile(r"^[\w-]+") - search_result = expression.search(self.selector) - if search_result is None: - return "" - else: - return search_result.group() - - def get_id(self) -> str: - expression = re.compile(r"#([\w-]+)") - search_result = expression.search( - ParsingUtils.remove_quoted_text(self.selector) - ) - if search_result is None: - return "" - else: - return search_result.group(1) - - def get_classes(self) -> List[str]: - expression = re.compile(r"\.([\w-]+)") - return expression.findall(ParsingUtils.remove_quoted_text(self.selector)) - - def get_attributes(self) -> Dict[str, str]: - attributes = {} - raw_attributes = re.compile(r"\[[^\[\]]+]").findall(self.selector) - for attribute in raw_attributes: - attribute_expression = re.compile(r"""\[([\w-]+)=('.*'|".*")]""") - attribute_match = attribute_expression.match(attribute) - if attribute_match is not None: - attributes[attribute_match.group(1)] = ( - attribute_match.group(2).strip("'").strip('"') - ) - return attributes - - -class XPathParser: - def __init__(self, selector: str): - self.selector = selector - self.validate() - - def validate(self) -> None: - expression = re.compile(r"^//([\w-]*|\*)(\[.+])*$") - if expression.match(self.selector) is None: - raise ParsingError("Cannot parse XPath selector.") - - def get_tag(self) -> str: - expression = re.compile(r"^//([\w-]+)") - search_result = expression.search(self.selector) - if search_result is None: - return "" - else: - return search_result.group(1) - - def get_id(self) -> str: - expression = re.compile(r"""@id=('[\w-]+'|"[\w-]+")""") - search_result = expression.search(self.selector) - if search_result is None: - return "" - else: - return search_result.group(1).strip('"').strip("'") - - def get_classes(self) -> List[str]: - expression_all_classes = r"""@class=('[ \w-]+'|"[ \w-]+")""" - expression_contains = r"""contains\(@class,('[ \w-]+'|"[ \w-]+")\)""" - for expression in [expression_all_classes, expression_contains]: - search_result = re.compile(expression).search(self.selector) - if search_result is not None: - return search_result.group(1).strip('"').strip("'").split(" ") - return [] - - def get_attributes(self) -> Dict[str, str]: - attributes = {} - attribute_expression = re.compile(r"""@([\w-]+)=('[^']*'|"[^"]*")""") - raw_attributes = attribute_expression.findall(self.selector) - for attr_name, attr_value in raw_attributes: - if attr_name not in ["class", "id"]: - attributes[attr_name] = attr_value.strip("'").strip('"') - return attributes - - def get_index(self) -> Optional[int]: - expression = re.compile(r"""\[(\d)+]""") - search_result = expression.search( - ParsingUtils.remove_quoted_text(self.selector) - ) - if search_result is None: - return None - else: - return int(search_result.group(1)) - - def get_inner_text(self) -> str: - expression = re.compile(r"""text\(\)=('[^']*'|"[^"]*")""") - search_result = expression.search(self.selector) - if search_result is None: - return "" - else: - return search_result.group(1)[1:-1] diff --git a/healenium/shell-installation/web/healenium-selector-imitator/src/selector_to_string.py b/healenium/shell-installation/web/healenium-selector-imitator/src/selector_to_string.py deleted file mode 100644 index 2ea9492..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/src/selector_to_string.py +++ /dev/null @@ -1,79 +0,0 @@ -from typing import List, Dict, Optional - - -class CSSSelectorConstructor: - def __init__( - self, - tag: Optional[str] = None, - element_id: Optional[str] = None, - classes: Optional[List[str]] = None, - other_attributes: Optional[Dict[str, str]] = None, - ): - self.tag = tag - self.element_id = element_id - if classes is not None: - self.classes = classes - else: - self.classes = [] - if other_attributes is not None: - self.other_attributes = other_attributes - else: - self.other_attributes = {} - - def get_string_representation(self) -> str: - result = "" - if self.tag is not None: - result += self.tag - if self.element_id is not None: - result += f"#{self.element_id}" - for class_name in self.classes: - result += f".{class_name}" - for attr_name, attr_value in self.other_attributes.items(): - result += f"[{attr_name}='{attr_value}']" - return result - - -class XPathConstructor: - def __init__( - self, - tag: Optional[str] = None, - element_id: Optional[str] = None, - classes: Optional[List[str]] = None, - other_attributes: Optional[Dict[str, str]] = None, - index: Optional[int] = None, - inner_text: Optional[str] = None, - ): - self.tag = tag - self.element_id = element_id - if classes is not None: - self.classes = classes - else: - self.classes = [] - if other_attributes is not None: - self.other_attributes = other_attributes - else: - self.other_attributes = {} - self.index = index - self.inner_text = inner_text - - def get_string_representation(self, split_classes: bool = False) -> str: - result = "//" - if self.tag is None: - result += "*" - else: - result += self.tag - if self.element_id is not None: - result += f"[@id='{self.element_id}']" - if split_classes: - for classname in self.classes: - result += f"[contains(@class, '{classname}')]" - elif self.classes: - merged_classes = " ".join(self.classes) - result += f"[@class='{merged_classes}']" - for attr_name, attr_value in self.other_attributes.items(): - result += f"[@{attr_name}='{attr_value}']" - if self.inner_text is not None: - result += f"[text()='{self.inner_text}']" - if self.index is not None: - result += f"[{self.index}]" - return result diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_api.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_api.py deleted file mode 100644 index 7e25754..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_api.py +++ /dev/null @@ -1,114 +0,0 @@ -import pytest - -from app import app -from fastapi.testclient import TestClient -from typing import List - - -@pytest.fixture() -def user_selector() -> dict: - return {"type": "By.xpath", "value": "//*[@value='Log In']"} - - -@pytest.fixture() -def user_selector_invalid_value() -> dict: - return {"type": "By.xpath", "value": "hello, world!"} - - -@pytest.fixture() -def target_node() -> dict: - return { - "tag": "input", - "classes": "fadeIn fourth", - "other": { - "_ngcontent-wvw-c3": "", - "type": "button", - "value": "Log In New", - }, - "parent": None, - "children": [], - } - - -@pytest.fixture() -def target_node_no_value() -> dict: - return { - "tag": "input", - "classes": "fadeIn fourth", - "other": { - "_ngcontent-wvw-c3": "", - "type": "button", - }, - "parent": None, - "children": [], - } - - -@pytest.fixture() -def expected_response() -> List[dict]: - return [{"type": "By.xpath", "value": "//*[@value='Log In New']"}] - - -@pytest.fixture() -def expected_response_imitation_error() -> dict: - return { - "detail": [ - { - "msg": "Unable to imitate the user selector: " - "Target node does not have an attribute value." - } - ] - } - - -@pytest.fixture() -def expected_response_parsing_error() -> dict: - return { - "detail": [ - { - "msg": "Unable to parse the user selector: " - "Cannot parse XPath selector." - } - ] - } - - -def test_main(): - with TestClient(app) as client: - response = client.get("/") - assert response.status_code == 200 - - -def test_imitate(user_selector: dict, target_node: dict, expected_response: List[dict]): - request_data = {"userSelector": user_selector, "targetNode": target_node} - with TestClient(app) as client: - response = client.post("/imitate", json=request_data) - assert response.status_code == 200 - assert response.json() == expected_response - - -def test_imitation_error( - user_selector: dict, - target_node_no_value: dict, - expected_response_imitation_error: List[dict], -): - request_data = {"userSelector": user_selector, "targetNode": target_node_no_value} - with TestClient(app) as client: - response = client.post("/imitate", json=request_data) - assert response.status_code == 422 - assert response.json() == expected_response_imitation_error - - -def test_parsing_error( - user_selector_invalid_value: dict, - target_node: dict, - expected_response_parsing_error: List[dict], -): - request_data = { - "userSelector": user_selector_invalid_value, - "targetNode": target_node, - } - with TestClient(app) as client: - response = client.post("/imitate", json=request_data) - assert response.status_code == 422 - assert response.json() == expected_response_parsing_error diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_class_name.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_class_name.py deleted file mode 100644 index f2b9b59..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_class_name.py +++ /dev/null @@ -1,40 +0,0 @@ -import pytest - -from src.node import Node -from src.selector import Selector, SelectorType -from src.selector_imitator import SelectorImitator, ImitationError - - -def test_imitate_by_class_name(): - user_selector = Selector( - selector_type=SelectorType.BY_CLASS_NAME, classes=["class1"] - ) - target_node = Node(classes=["class2"]) - expected_result = Selector( - selector_type=SelectorType.BY_CLASS_NAME, classes=["class2"] - ) - imitated_selectors = SelectorImitator(user_selector, target_node).imitate() - assert len(imitated_selectors) == 1 - assert imitated_selectors[0] == expected_result - - -def test_imitate_by_class_name_two_classes(): - user_selector = Selector( - selector_type=SelectorType.BY_CLASS_NAME, classes=["class1"] - ) - target_node = Node(classes=["class2", "class3"]) - expected_result = [ - Selector(selector_type=SelectorType.BY_CLASS_NAME, classes=["class2"]), - Selector(selector_type=SelectorType.BY_CLASS_NAME, classes=["class3"]), - ] - imitated_selectors = SelectorImitator(user_selector, target_node).imitate() - assert expected_result == imitated_selectors - - -def test_imitate_by_class_name_invalid_target(): - user_selector = Selector( - selector_type=SelectorType.BY_CLASS_NAME, classes=["class1"] - ) - target_node = Node(tag="p", id="some_id") - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_css_selector.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_css_selector.py deleted file mode 100644 index f391b27..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_css_selector.py +++ /dev/null @@ -1,46 +0,0 @@ -import pytest - -from src.node import Node -from src.selector import Selector, SelectorType -from src.selector_imitator import SelectorImitator, ImitationError - - -def test_imitate_by_css_selector(): - user_selector = Selector( - selector_type=SelectorType.BY_CSS_SELECTOR, - tag="img", - other_attributes={"name": "some_name"}, - ) - target_node = Node(tag="img", other_attributes={"name": "name2"}) - expected_result = Selector( - selector_type=SelectorType.BY_CSS_SELECTOR, - tag="img", - other_attributes={"name": "name2"}, - ) - imitated_selectors = SelectorImitator(user_selector, target_node).imitate() - assert len(imitated_selectors) == 1 - assert imitated_selectors[0] == expected_result - - -def test_imitate_by_css_selector_invalid_attributes(): - user_selector = Selector( - selector_type=SelectorType.BY_CSS_SELECTOR, - classes=["class1"], - other_attributes={"name": "some_name"}, - ) - target_node = Node( - classes=["class2", "class3"], other_attributes={"src": "img.png"} - ) - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() - - -def test_imitate_by_css_selector_invalid_target(): - user_selector = Selector( - selector_type=SelectorType.BY_CSS_SELECTOR, - tag="img", - other_attributes={"name": "some_name"}, - ) - target_node = Node(other_attributes={"name": "some_name"}) - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_id.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_id.py deleted file mode 100644 index db36557..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_id.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest - -from src.node import Node -from src.selector import Selector, SelectorType -from src.selector_imitator import SelectorImitator, ImitationError - - -def test_imitate_by_id(): - user_selector = Selector(selector_type=SelectorType.BY_ID, id="element1") - target_node = Node(tag="h1", id="element2") - expected_result = Selector(selector_type=SelectorType.BY_ID, id="element2") - imitated_selectors = SelectorImitator(user_selector, target_node).imitate() - assert len(imitated_selectors) == 1 - assert imitated_selectors[0] == expected_result - - -def test_imitate_by_id_invalid_target(): - user_selector = Selector(selector_type=SelectorType.BY_ID, id="element1") - target_node = Node(tag="p", other_attributes={"name": "element1"}) - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_link_text.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_link_text.py deleted file mode 100644 index 9f3aea6..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_link_text.py +++ /dev/null @@ -1,30 +0,0 @@ -import pytest - -from src.node import Node -from src.selector import Selector, SelectorType -from src.selector_imitator import SelectorImitator, ImitationError - - -def test_imitate_by_link_text(): - user_selector = Selector(selector_type=SelectorType.BY_LINK_TEXT, inner_text="link") - target_node = Node(tag="a", inner_text="link to external page") - expected_result = Selector( - selector_type=SelectorType.BY_LINK_TEXT, inner_text="link to external page" - ) - imitated_selectors = SelectorImitator(user_selector, target_node).imitate() - assert len(imitated_selectors) == 1 - assert imitated_selectors[0] == expected_result - - -def test_imitate_by_link_text_not_anchor(): - user_selector = Selector(selector_type=SelectorType.BY_LINK_TEXT, inner_text="link") - target_node = Node(tag="p", inner_text="link to external page") - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() - - -def test_imitate_by_link_text_invalid_target(): - user_selector = Selector(selector_type=SelectorType.BY_LINK_TEXT, inner_text="link") - target_node = Node(tag="a", inner_text="") - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_name.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_name.py deleted file mode 100644 index 214afbc..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_name.py +++ /dev/null @@ -1,34 +0,0 @@ -import pytest - -from src.node import Node -from src.selector import Selector, SelectorType -from src.selector_imitator import SelectorImitator, ImitationError - - -def test_imitate_by_name(): - user_selector = Selector( - selector_type=SelectorType.BY_NAME, other_attributes={"name": "element1"} - ) - target_node = Node(tag="h1", other_attributes={"name": "element_1"}) - expected_result = Selector( - selector_type=SelectorType.BY_NAME, other_attributes={"name": "element_1"} - ) - imitated_selectors = SelectorImitator(user_selector, target_node).imitate() - assert len(imitated_selectors) == 1 - assert imitated_selectors[0] == expected_result - - -def test_imitate_by_name_invalid_target(): - user_selector = Selector( - selector_type=SelectorType.BY_NAME, other_attributes={"name": "element1"} - ) - target_node = Node(tag="h1") - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() - - -def test_imitate_by_name_invalid_user_selector(): - user_selector = Selector(selector_type=SelectorType.BY_NAME) - target_node = Node(tag="h1", other_attributes={"name": "element_1"}) - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_partial_link_text.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_partial_link_text.py deleted file mode 100644 index bada68f..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_partial_link_text.py +++ /dev/null @@ -1,37 +0,0 @@ -import pytest - -from src.node import Node -from src.selector import Selector, SelectorType -from src.selector_imitator import SelectorImitator, ImitationError - - -def test_imitate_by_partial_link_text(): - user_selector = Selector( - selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, inner_text="link" - ) - target_node = Node(tag="a", inner_text="link to external page") - expected_result = Selector( - selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, - inner_text="link to external page", - ) - imitated_selectors = SelectorImitator(user_selector, target_node).imitate() - assert len(imitated_selectors) == 1 - assert imitated_selectors[0] == expected_result - - -def test_imitate_by_partial_link_text_not_anchor(): - user_selector = Selector( - selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, inner_text="link" - ) - target_node = Node(tag="p", inner_text="link to external page") - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() - - -def test_imitate_by_partial_link_text_invalid_target(): - user_selector = Selector( - selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, inner_text="link" - ) - target_node = Node(tag="a", inner_text="") - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_tag_name.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_tag_name.py deleted file mode 100644 index 81ac612..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_tag_name.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest - -from src.node import Node -from src.selector import Selector, SelectorType -from src.selector_imitator import SelectorImitator, ImitationError - - -def test_imitate_by_tag_name(): - user_selector = Selector(selector_type=SelectorType.BY_TAG_NAME, tag="h1") - target_node = Node(tag="h2", id="element2") - expected_result = Selector(selector_type=SelectorType.BY_TAG_NAME, tag="h2") - imitated_selectors = SelectorImitator(user_selector, target_node).imitate() - assert len(imitated_selectors) == 1 - assert imitated_selectors[0] == expected_result - - -def test_imitate_by_tag_name_invalid_target(): - user_selector = Selector(selector_type=SelectorType.BY_TAG_NAME, tag="h1") - target_node = Node(other_attributes={"name": "element1"}) - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_xpath.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_xpath.py deleted file mode 100644 index 092af98..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_by_xpath.py +++ /dev/null @@ -1,46 +0,0 @@ -import pytest - -from src.node import Node -from src.selector import Selector, SelectorType -from src.selector_imitator import SelectorImitator, ImitationError - - -def test_imitate_by_xpath(): - user_selector = Selector( - selector_type=SelectorType.BY_XPATH, - tag="img", - other_attributes={"name": "some_name"}, - ) - target_node = Node(tag="img", other_attributes={"name": "name2"}) - expected_result = Selector( - selector_type=SelectorType.BY_XPATH, - tag="img", - other_attributes={"name": "name2"}, - ) - imitated_selectors = SelectorImitator(user_selector, target_node).imitate() - assert len(imitated_selectors) == 1 - assert imitated_selectors[0] == expected_result - - -def test_imitate_by_xpath_invalid_attributes(): - user_selector = Selector( - selector_type=SelectorType.BY_XPATH, - classes=["class1"], - other_attributes={"name": "some_name"}, - ) - target_node = Node( - classes=["class2", "class3"], other_attributes={"src": "img.png"} - ) - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() - - -def test_imitate_by_xpath_invalid_target(): - user_selector = Selector( - selector_type=SelectorType.BY_XPATH, - tag="img", - other_attributes={"name": "some_name"}, - ) - target_node = Node(other_attributes={"name": "some_name"}) - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_unimplemented.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_unimplemented.py deleted file mode 100644 index 067aada..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_imitate/test_imitate_unimplemented.py +++ /dev/null @@ -1,16 +0,0 @@ -import pytest - -from src.node import Node -from src.selector import Selector -from src.selector_imitator import SelectorImitator, ImitationError - - -def test_imitate_unimplemented(): - user_selector = Selector( - selector_type=42, - tag="img", - other_attributes={"name": "some_name"}, - ) - target_node = Node(other_attributes={"name": "some_name"}) - with pytest.raises(ImitationError): - SelectorImitator(user_selector, target_node).imitate() diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_integration.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_integration.py deleted file mode 100644 index 8cafefe..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_integration.py +++ /dev/null @@ -1,86 +0,0 @@ -from src.node import Node -from src.selector import Selector -from src.selector_imitator import SelectorImitator - - -def test_integration_css_selector_name(): - user_selector = Selector.from_css("div[name='old_name']") - target_node = Node( - tag="div", - id="my_div", - classes=["cls1", "class2"], - index=1, - other_attributes={"name": "new_name", "href": "some_link"}, - inner_text="hello world", - ) - assert ( - str(SelectorImitator(user_selector, target_node).imitate()[0]) - == "div[name='new_name']" - ) - - -def test_integration_css_selector_tag(): - user_selector = Selector.from_css("h1.cls1[name='some_name']") - target_node = Node( - tag="h2", - id="my_div", - classes=["cls1", "class2"], - index=1, - other_attributes={"name": "some_name", "href": "some_link"}, - inner_text="hello world", - ) - assert ( - str(SelectorImitator(user_selector, target_node).imitate()[0]) - == "h2.cls1[name='some_name']" - ) - - -def test_integration_xpath_selector_value(): - user_selector = Selector.from_xpath("//*[@value='Log In']") - target_node = Node( - tag="input", - classes=["fadeIn", "fourth"], - other_attributes={ - "_ngcontent-wvw-c3": "", - "type": "button", - "value": "Log In New", - }, - ) - assert ( - str(SelectorImitator(user_selector, target_node).imitate()[0]) - == "//*[@value='Log In New']" - ) - - -def test_integration_xpath_selector_class_split(): - user_selector = Selector.from_xpath("//*[@class='fadeIn'][@value='Log In']") - target_node = Node( - tag="input", - classes=["fadeIn", "fourth"], - other_attributes={ - "_ngcontent-wvw-c3": "", - "type": "button", - "value": "Log In New", - }, - ) - assert ( - str(SelectorImitator(user_selector, target_node).imitate()[0]) - == "//*[contains(@class, 'fadeIn')][@value='Log In New']" - ) - - -def test_integration_xpath_selector_class_no_split(): - user_selector = Selector.from_xpath("//*[@class='fadeIn fourth'][@value='Log In']") - target_node = Node( - tag="input", - classes=["fadeIn", "fourth"], - other_attributes={ - "_ngcontent-wvw-c3": "", - "type": "button", - "value": "Log In New", - }, - ) - assert ( - str(SelectorImitator(user_selector, target_node).imitate()[0]) - == "//*[@class='fadeIn fourth'][@value='Log In New']" - ) diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_css_parser.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_css_parser.py deleted file mode 100644 index 30108a4..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_css_parser.py +++ /dev/null @@ -1,66 +0,0 @@ -import pytest - -from src.selector_parser import CSSSelectorParser, ParsingError - - -def test_validation_success_simple(): - CSSSelectorParser("p") - - -def test_validation_success_complex(): - CSSSelectorParser("div#hello.class_name[href='hello world']") - - -def test_validation_error(): - with pytest.raises(ParsingError): - CSSSelectorParser("div#hello_world span.some_class") - - -def test_parse_tag(): - selector = "div#hello.class_name[href='hello world']" - assert CSSSelectorParser(selector).get_tag() == "div" - - -def test_parse_no_tag(): - selector = "#hello.class_name[href='hello world']" - assert CSSSelectorParser(selector).get_tag() == "" - - -def test_parse_tag_simple(): - selector = "div" - assert CSSSelectorParser(selector).get_tag() == "div" - - -def test_parse_id(): - selector = "div#hello-world.class_name[href='hello world']" - assert CSSSelectorParser(selector).get_id() == "hello-world" - - -def test_parse_id_empty(): - selector = "div.class_name[href='hello #world']" - assert CSSSelectorParser(selector).get_id() == "" - - -def test_parse_classes(): - selector = "div#hello.class_name.class_2[href='hello world']" - assert set(CSSSelectorParser(selector).get_classes()) == {"class_name", "class_2"} - - -def test_parse_classes_empty(): - selector = "div#hello[href='hello.world']" - assert set(CSSSelectorParser(selector).get_classes()) == set() - - -def test_parse_attributes_single_quotes(): - selector = "div#hello[href='hello.world']" - assert CSSSelectorParser(selector).get_attributes() == {"href": "hello.world"} - - -def test_parse_attributes_double_quotes(): - selector = 'div.class_hello[name="hello"]' - assert CSSSelectorParser(selector).get_attributes() == {"name": "hello"} - - -def test_parse_attributes_empty(): - selector = "div.class_hello" - assert CSSSelectorParser(selector).get_attributes() == {} diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_xpath_parser.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_xpath_parser.py deleted file mode 100644 index 199c7ad..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_parser/test_xpath_parser.py +++ /dev/null @@ -1,98 +0,0 @@ -import pytest - -from src.selector_parser import XPathParser, ParsingError - - -def test_validation_success_simple(): - XPathParser("//p") - - -def test_validation_success_complex(): - XPathParser("//label[@id='message23']") - - -def test_validation_success_no_tag(): - XPathParser("//*[@class='cls1'][1]") - - -def test_validation_error(): - with pytest.raises(ParsingError): - XPathParser("//*[@type='text']//following::input") - - -def test_parse_tag(): - assert XPathParser("//label[@id='message23']").get_tag() == "label" - - -def test_parse_tag_simple(): - assert XPathParser("//h2").get_tag() == "h2" - - -def test_parse_no_tag(): - assert XPathParser("//*[@class='cls1'][1]").get_tag() == "" - - -def test_parse_id(): - assert XPathParser("//*[@id='rt-feature']").get_id() == "rt-feature" - - -def test_parse_no_id(): - assert XPathParser("//*[@class='cls1'][1]").get_id() == "" - - -def test_parse_classes_single_class(): - assert XPathParser("//*[@class='cls1'][1]").get_classes() == ["cls1"] - - -def test_parse_classes_multiple_classes(): - assert XPathParser("//*[@class='cls1 cls2'][1]").get_classes() == ["cls1", "cls2"] - - -def test_parse_classes_single_class_with_contains(): - assert XPathParser("//*[contains(@class,'btn')]").get_classes() == ["btn"] - - -def test_parse_classes_multiple_classes_with_contains(): - assert XPathParser("//*[contains(@class,'btn cls1')]").get_classes() == [ - "btn", - "cls1", - ] - - -def test_parse_classes_no_class(): - assert XPathParser("//label[@id='message23']").get_classes() == [] - - -def test_parse_attributes_single_quotes(): - selector = "//div[@id='hello'][@href='hello.world']" - assert XPathParser(selector).get_attributes() == {"href": "hello.world"} - - -def test_parse_attributes_double_quotes(): - selector = '//*[@class="class-hello" and @name="hello"]' - assert XPathParser(selector).get_attributes() == {"name": "hello"} - - -def test_parse_attributes_empty(): - selector = "//*[@class='class-hello']" - assert XPathParser(selector).get_attributes() == {} - - -def test_parse_index(): - selector = "//*[@class='cls1 cls2'][2]" - assert XPathParser(selector).get_index() == 2 - - -def test_parse_index_no_index(): - selector = "//div[@id='hello'][@href='hello.world']" - assert XPathParser(selector).get_index() is None - - -def test_parse_inner_text(): - selector = "//p[@class='cls1 cls2' and text()='Hello, World!'][2]" - assert XPathParser(selector).get_inner_text() == "Hello, World!" - - -def test_parse_inner_text_empty(): - selector = "//p[@class='cls1 cls2'][2]" - assert XPathParser(selector).get_inner_text() == "" diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_from_string.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_from_string.py deleted file mode 100644 index 976e13b..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_from_string.py +++ /dev/null @@ -1,81 +0,0 @@ -from src.selector import Selector, SelectorType - - -def test_from_class_name(): - assert Selector.from_class_name("cls") == Selector( - selector_type=SelectorType.BY_CLASS_NAME, classes=["cls"] - ) - - -def test_from_css_simple(): - css_selector = "div" - assert Selector.from_css(css_selector) == Selector( - selector_type=SelectorType.BY_CSS_SELECTOR, tag="div" - ) - - -def test_from_css_complex(): - css_selector = "div#hello.class_name.cls2[href='hello world']" - assert Selector.from_css(css_selector) == Selector( - selector_type=SelectorType.BY_CSS_SELECTOR, - tag="div", - id="hello", - classes=["class_name", "cls2"], - other_attributes={"href": "hello world"}, - ) - - -def test_from_id(): - assert Selector.from_id("hello") == Selector( - selector_type=SelectorType.BY_ID, id="hello" - ) - - -def test_from_link_text(): - assert Selector.from_link_text("hello_world") == Selector( - selector_type=SelectorType.BY_LINK_TEXT, inner_text="hello_world" - ) - - -def test_from_name(): - assert Selector.from_name("some_name") == Selector( - selector_type=SelectorType.BY_NAME, other_attributes={"name": "some_name"} - ) - - -def test_from_partial_link_text(): - assert Selector.from_partial_link_text("hello_world") == Selector( - selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, inner_text="hello_world" - ) - - -def test_from_tag_name(): - assert Selector.from_tag_name("h3") == Selector( - selector_type=SelectorType.BY_TAG_NAME, tag="h3" - ) - - -def test_from_xpath_simple(): - xpath_selector = "//div" - assert Selector.from_xpath(xpath_selector) == Selector( - selector_type=SelectorType.BY_XPATH, tag="div" - ) - - -def test_from_xpath_complex(): - xpath_selector = ( - "//div[@name='my_selector'][@class='classname cls2' and text()='hello world']" - ) - assert Selector.from_xpath(xpath_selector) == Selector( - selector_type=SelectorType.BY_XPATH, - tag="div", - classes=["classname", "cls2"], - other_attributes={"name": "my_selector"}, - inner_text="hello world", - ) - - -def test_from_type_and_value(): - assert Selector.from_type_and_value( - SelectorType.BY_ID, value="some-id" - ) == Selector(selector_type=SelectorType.BY_ID, id="some-id") diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_to_string.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_to_string.py deleted file mode 100644 index 0e130c2..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector/test_selector_to_string.py +++ /dev/null @@ -1,83 +0,0 @@ -import pytest - -from src.selector import Selector, SelectorType - - -def test_class_name_selector_to_string(): - assert ( - str(Selector(selector_type=SelectorType.BY_CLASS_NAME, classes=["clsname"])) - == "clsname" - ) - - -def test_class_name_selector_to_string_many_classes(): - with pytest.raises(ValueError): - str( - Selector(selector_type=SelectorType.BY_CLASS_NAME, classes=["cls1", "cls2"]) - ) - - -def test_class_name_selector_to_string_no_class(): - with pytest.raises(ValueError): - str(Selector(selector_type=SelectorType.BY_CLASS_NAME)) - - -def test_css_selector_to_string(): - assert ( - str(Selector(selector_type=SelectorType.BY_CSS_SELECTOR, tag="h2", id="hello")) - == "h2#hello" - ) - - -def test_id_selector_to_string(): - assert str(Selector(selector_type=SelectorType.BY_ID, id="hello")) == "hello" - - -def test_link_text_selector_to_string(): - assert ( - str(Selector(selector_type=SelectorType.BY_LINK_TEXT, inner_text="hello world")) - == "hello world" - ) - - -def test_name_selector_to_string(): - assert ( - str( - Selector( - selector_type=SelectorType.BY_NAME, other_attributes={"name": "hello"} - ) - ) - == "hello" - ) - - -def test_name_selector_to_string_no_name(): - with pytest.raises(ValueError): - str( - Selector( - selector_type=SelectorType.BY_NAME, other_attributes={"value": "hello"} - ) - ) - - -def test_partial_link_text_selector_to_string(): - assert ( - str( - Selector( - selector_type=SelectorType.BY_PARTIAL_LINK_TEXT, - inner_text="hello world", - ) - ) - == "hello world" - ) - - -def test_tag_selector_to_string(): - assert str(Selector(selector_type=SelectorType.BY_TAG_NAME, tag="div")) == "div" - - -def test_xpath_selector_to_string(): - assert ( - str(Selector(selector_type=SelectorType.BY_XPATH, tag="h2", id="hello")) - == "//h2[@id='hello']" - ) diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/__init__.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_css_selector_constructor.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_css_selector_constructor.py deleted file mode 100644 index 5885090..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_css_selector_constructor.py +++ /dev/null @@ -1,40 +0,0 @@ -from src.selector_to_string import CSSSelectorConstructor - - -def test_css_constructor_only_tag(): - assert CSSSelectorConstructor(tag="h2").get_string_representation() == "h2" - - -def test_css_constructor_only_id(): - assert ( - CSSSelectorConstructor(element_id="hello").get_string_representation() - == "#hello" - ) - - -def test_css_constructor_id_with_tag(): - assert ( - CSSSelectorConstructor(tag="h2", element_id="hello").get_string_representation() - == "h2#hello" - ) - - -def test_css_constructor_id_with_tag_and_classes(): - assert ( - CSSSelectorConstructor( - tag="h2", element_id="hello", classes=["class1", "cls2"] - ).get_string_representation() - == "h2#hello.class1.cls2" - ) - - -def test_css_constructor_all_elements(): - assert ( - CSSSelectorConstructor( - tag="h2", - element_id="hello", - classes=["class1", "cls2"], - other_attributes={"href": "hello world"}, - ).get_string_representation() - == "h2#hello.class1.cls2[href='hello world']" - ) diff --git a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_xpath_constructor.py b/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_xpath_constructor.py deleted file mode 100644 index 37ded56..0000000 --- a/healenium/shell-installation/web/healenium-selector-imitator/test/test_selector_to_string/test_xpath_constructor.py +++ /dev/null @@ -1,52 +0,0 @@ -from src.selector_to_string import XPathConstructor - - -def test_xpath_constructor_only_tag(): - assert XPathConstructor(tag="h2").get_string_representation() == "//h2" - - -def test_xpath_constructor_only_id(): - assert ( - XPathConstructor(element_id="hello").get_string_representation() - == "//*[@id='hello']" - ) - - -def test_xpath_constructor_id_with_tag(): - assert ( - XPathConstructor(tag="h2", element_id="hello").get_string_representation() - == "//h2[@id='hello']" - ) - - -def test_xpath_constructor_id_with_tag_and_classes(): - assert ( - XPathConstructor( - tag="h2", element_id="hello", classes=["class1", "cls2"] - ).get_string_representation() - == "//h2[@id='hello'][@class='class1 cls2']" - ) - - -def test_xpath_constructor_id_with_tag_and_classes_split(): - assert ( - XPathConstructor( - tag="h2", element_id="hello", classes=["class1", "cls2"] - ).get_string_representation(split_classes=True) - == "//h2[@id='hello'][contains(@class, 'class1')][contains(@class, 'cls2')]" - ) - - -def test_xpath_constructor_all_elements(): - assert ( - XPathConstructor( - tag="h2", - element_id="hello", - classes=["cls1"], - other_attributes={"value": "42"}, - index=11, - inner_text="Hello, World!", - ).get_string_representation() - == "//h2[@id='hello'][@class='cls1']" - "[@value='42'][text()='Hello, World!'][11]" - ) From 4920855a6be0493a83161c6ec663ded0450380d1 Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Sun, 8 Oct 2023 23:17:24 +0300 Subject: [PATCH 20/24] update to 1.3.6 --- healenium/docker-compose-appium.yaml | 5 +++-- healenium/docker-compose-selenoid.yaml | 3 ++- healenium/docker-compose-web.yaml | 2 +- healenium/docker-compose.yaml | 5 +++-- .../shell-installation/selenium-grid/download_services.sh | 4 ++-- healenium/shell-installation/web/download_services.sh | 2 +- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/healenium/docker-compose-appium.yaml b/healenium/docker-compose-appium.yaml index 5798f36..4abf355 100644 --- a/healenium/docker-compose-appium.yaml +++ b/healenium/docker-compose-appium.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.4.0 + image: healenium/hlm-backend:3.4.1 container_name: healenium restart: on-failure ports: @@ -33,6 +33,7 @@ services: - 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 @@ -50,7 +51,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.3.5 + image: healenium/hlm-proxy:1.3.6 container_name: hlm-proxy restart: on-failure ports: diff --git a/healenium/docker-compose-selenoid.yaml b/healenium/docker-compose-selenoid.yaml index 1b9f599..8dd517c 100644 --- a/healenium/docker-compose-selenoid.yaml +++ b/healenium/docker-compose-selenoid.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.4.0 + image: healenium/hlm-backend:3.4.1 container_name: healenium restart: on-failure ports: @@ -33,6 +33,7 @@ services: - 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 diff --git a/healenium/docker-compose-web.yaml b/healenium/docker-compose-web.yaml index 3df5fa1..230eb62 100644 --- a/healenium/docker-compose-web.yaml +++ b/healenium/docker-compose-web.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.4.0 + image: healenium/hlm-backend:3.4.1 container_name: healenium restart: on-failure ports: diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index 96d2316..3c1a74f 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -18,7 +18,7 @@ services: - healenium healenium: - image: healenium/hlm-backend:3.4.0 + image: healenium/hlm-backend:3.4.1 container_name: healenium restart: on-failure ports: @@ -33,6 +33,7 @@ services: - 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 @@ -50,7 +51,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.3.5 + image: healenium/hlm-proxy:1.3.6 container_name: hlm-proxy restart: on-failure ports: diff --git a/healenium/shell-installation/selenium-grid/download_services.sh b/healenium/shell-installation/selenium-grid/download_services.sh index 7749340..81a58f4 100644 --- a/healenium/shell-installation/selenium-grid/download_services.sh +++ b/healenium/shell-installation/selenium-grid/download_services.sh @@ -1,8 +1,8 @@ #!/bin/bash # Versions of the services -HLM_BACKEND_VERSION="3.4.0" -HLM_PROXY_VERSION="1.3.5" +HLM_BACKEND_VERSION="3.4.1" +HLM_PROXY_VERSION="1.3.6" # Downloading curl -L https://github.com/healenium/healenium-backend/releases/download/${HLM_BACKEND_VERSION}/healenium-backend-${HLM_BACKEND_VERSION}.jar > hlm-backend.jar diff --git a/healenium/shell-installation/web/download_services.sh b/healenium/shell-installation/web/download_services.sh index e13a8f6..811a7d1 100644 --- a/healenium/shell-installation/web/download_services.sh +++ b/healenium/shell-installation/web/download_services.sh @@ -1,7 +1,7 @@ #!/bin/bash # Versions of the services -HLM_BACKEND_VERSION="3.4.0" +HLM_BACKEND_VERSION="3.4.1" # Downloading curl -L https://github.com/healenium/healenium-backend/releases/download/${HLM_BACKEND_VERSION}/healenium-backend-${HLM_BACKEND_VERSION}.jar > hlm-backend.jar From f5ed26ecb7c2e811aaa3d328d29ddb944c8800cb Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Tue, 22 Oct 2024 18:00:48 +0300 Subject: [PATCH 21/24] update to 2.1.1 --- README.md | 8 ++++++++ src/main/pages/callback_page.py | 8 ++++++-- src/main/pages/testenv_page.py | 14 +++++++++++++ tests/test_wait.py | 36 ++++++++++++++------------------- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 7264f71..e1b14f3 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,14 @@ To run using Healenium create RemoteWebDriver with URL ```http:// Date: Wed, 23 Oct 2024 03:16:59 +0300 Subject: [PATCH 22/24] update to 2.1.1 --- src/main/pages/testenv_page.py | 11 ++++------- tests/test_wait.py | 6 +++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/pages/testenv_page.py b/src/main/pages/testenv_page.py index 4525f7d..65916b8 100644 --- a/src/main/pages/testenv_page.py +++ b/src/main/pages/testenv_page.py @@ -53,14 +53,11 @@ def find_test_element(self, locator_type, selector): def click_wait_btn(self): self.driver.find_element(By.ID, "Wait_Submit").click() - def disable_healing_true(self): - self.driver.execute_script("disable_healing_true") + def execute_script(self, script): + self.driver.execute_script(script) - def disable_healing_false(self): - self.driver.execute_script("disable_healing_false") - - def click_test_button_wait(self, seconds): - WebDriverWait(self.driver, seconds).until(ec.visibility_of_element_located((By.ID, "wait_new_element"))) + 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_wait.py b/tests/test_wait.py index 6beef0a..9c7e021 100644 --- a/tests/test_wait.py +++ b/tests/test_wait.py @@ -8,8 +8,8 @@ def test_conditional_wait(self): test_page.open_browser() test_page.click_wait_btn() - test_page.disable_healing_true() - test_page.click_test_button_wait(10) - test_page.disable_healing_false() + test_page.execute_script("disable_healing_true") + test_page.click_test_button_wait() + test_page.execute_script("disable_healing_false") test_page.close() From 8fb3ed9aa5e963572cd77f20f66045982fc3a472 Mon Sep 17 00:00:00 2001 From: Aliaksei_Ashukha Date: Wed, 23 Oct 2024 13:37:27 +0300 Subject: [PATCH 23/24] update to 2.1.1 --- healenium/docker-compose-appium.yaml | 11 +++++------ healenium/docker-compose-selenoid.yaml | 9 ++++----- healenium/docker-compose-web.yaml | 6 +++--- healenium/docker-compose.yaml | 9 ++++----- .../selenium-grid/download_services.sh | 4 ++-- .../selenium-grid/start_healenium.sh | 3 +-- healenium/shell-installation/web/download_services.sh | 2 +- 7 files changed, 20 insertions(+), 24 deletions(-) diff --git a/healenium/docker-compose-appium.yaml b/healenium/docker-compose-appium.yaml index 4abf355..d1472db 100644 --- a/healenium/docker-compose-appium.yaml +++ b/healenium/docker-compose-appium.yaml @@ -3,7 +3,7 @@ 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:3.4.1 + image: healenium/hlm-backend:3.4.6 container_name: healenium restart: on-failure ports: @@ -42,7 +42,7 @@ services: - healenium selector-imitator: - image: healenium/hlm-selector-imitator:1.2 + image: healenium/hlm-selector-imitator:1.4 container_name: selector-imitator restart: on-failure ports: @@ -51,7 +51,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.3.6 + image: healenium/hlm-proxy:2.1.1 container_name: hlm-proxy restart: on-failure ports: @@ -60,8 +60,7 @@ services: - RECOVERY_TRIES=1 - SCORE_CAP=.6 - HEAL_ENABLED=true - - SELENIUM_SERVER_URL=http://hlm-selenoid:4444/wd/hub - - APPIUM_SERVER_URL=http://host.docker.internal:4723/wd/hub + - 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 diff --git a/healenium/docker-compose-selenoid.yaml b/healenium/docker-compose-selenoid.yaml index 8dd517c..3cba688 100644 --- a/healenium/docker-compose-selenoid.yaml +++ b/healenium/docker-compose-selenoid.yaml @@ -3,7 +3,7 @@ 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:3.4.1 + image: healenium/hlm-backend:3.4.6 container_name: healenium restart: on-failure ports: @@ -42,7 +42,7 @@ services: - healenium selector-imitator: - image: healenium/hlm-selector-imitator:1.2 + image: healenium/hlm-selector-imitator:1.4 container_name: selector-imitator restart: on-failure ports: @@ -51,7 +51,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.3.5 + image: healenium/hlm-proxy:2.1.1 container_name: hlm-proxy restart: on-failure ports: @@ -61,7 +61,6 @@ services: - SCORE_CAP=.6 - HEAL_ENABLED=true - SELENIUM_SERVER_URL=http://selenoid:4444/wd/hub - - APPIUM_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 diff --git a/healenium/docker-compose-web.yaml b/healenium/docker-compose-web.yaml index 230eb62..12f9291 100644 --- a/healenium/docker-compose-web.yaml +++ b/healenium/docker-compose-web.yaml @@ -3,7 +3,7 @@ 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:3.4.1 + image: healenium/hlm-backend:3.4.6 container_name: healenium restart: on-failure ports: @@ -41,7 +41,7 @@ services: - healenium selector-imitator: - image: healenium/hlm-selector-imitator:1.2 + image: healenium/hlm-selector-imitator:1.4 container_name: selector-imitator restart: on-failure ports: diff --git a/healenium/docker-compose.yaml b/healenium/docker-compose.yaml index 3c1a74f..2a8ff27 100644 --- a/healenium/docker-compose.yaml +++ b/healenium/docker-compose.yaml @@ -3,7 +3,7 @@ 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:3.4.1 + image: healenium/hlm-backend:3.4.6 container_name: healenium restart: on-failure ports: @@ -42,7 +42,7 @@ services: - healenium selector-imitator: - image: healenium/hlm-selector-imitator:1.2 + image: healenium/hlm-selector-imitator:1.4 container_name: selector-imitator restart: on-failure ports: @@ -51,7 +51,7 @@ services: - healenium hlm-proxy: - image: healenium/hlm-proxy:1.3.6 + image: healenium/hlm-proxy:2.1.1 container_name: hlm-proxy restart: on-failure ports: @@ -61,7 +61,6 @@ services: - SCORE_CAP=.6 - HEAL_ENABLED=true - SELENIUM_SERVER_URL=http://selenium-hub:4444/wd/hub - - APPIUM_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 diff --git a/healenium/shell-installation/selenium-grid/download_services.sh b/healenium/shell-installation/selenium-grid/download_services.sh index 81a58f4..90b33c1 100644 --- a/healenium/shell-installation/selenium-grid/download_services.sh +++ b/healenium/shell-installation/selenium-grid/download_services.sh @@ -1,8 +1,8 @@ #!/bin/bash # Versions of the services -HLM_BACKEND_VERSION="3.4.1" -HLM_PROXY_VERSION="1.3.6" +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 diff --git a/healenium/shell-installation/selenium-grid/start_healenium.sh b/healenium/shell-installation/selenium-grid/start_healenium.sh index 90d8e87..88fe583 100644 --- a/healenium/shell-installation/selenium-grid/start_healenium.sh +++ b/healenium/shell-installation/selenium-grid/start_healenium.sh @@ -14,7 +14,6 @@ RECOVERY_TRIES=1 SCORE_CAP=.6 HEAL_ENABLED=true SELENIUM_SERVER_URL=http://localhost:4444 -APPIUM_SERVER_URL=http://localhost:4723/wd/hub HEALENIUM_SERVER_URL=http://localhost:7878 HEALENIUM_SERVICE=http://localhost:7878 IMITATE_SERVICE=http://localhost:8000 @@ -23,7 +22,7 @@ IMITATE_SERVICE=http://localhost:8000 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 APPIUM_SERVER_URL=$APPIUM_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 & +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 diff --git a/healenium/shell-installation/web/download_services.sh b/healenium/shell-installation/web/download_services.sh index 811a7d1..a35c6be 100644 --- a/healenium/shell-installation/web/download_services.sh +++ b/healenium/shell-installation/web/download_services.sh @@ -1,7 +1,7 @@ #!/bin/bash # Versions of the services -HLM_BACKEND_VERSION="3.4.1" +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 From 78915cf1539a7d17c4cde6c62f8c3545ad26ca92 Mon Sep 17 00:00:00 2001 From: helen_yrofeeva Date: Mon, 2 Mar 2026 19:05:26 +0300 Subject: [PATCH 24/24] [EPMHLM-501] update test-env link --- src/main/pages/base_page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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