-
Notifications
You must be signed in to change notification settings - Fork 1
395 selenium #436
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
395 selenium #436
Changes from 13 commits
f8053a3
49b32a5
13c445f
69db029
7927bfa
8203e99
b950b60
c467d56
eee9bca
b3d0aca
373f8ea
ef9eea4
05b341f
71c133d
9c7e47e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,4 +6,3 @@ venv | |
| __pycache__ | ||
| Dockerfile* | ||
| app/playground | ||
| tests/selenium | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| .venv | ||
| venv | ||
| .venv | ||
| .idea | ||
| ssl | ||
| __pycache__ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| FROM selenium/standalone-chrome:137.0-chromedriver-137.0-grid-4.33.0-20250606 | ||
|
|
||
| WORKDIR /usr/src/project | ||
|
|
||
| USER root | ||
| RUN apt-get update && \ | ||
| apt-get install -y python3 python3-pip && \ | ||
| rm -rf /var/lib/apt/lists/* | ||
|
|
||
| COPY tests/requirements.txt requirements.txt | ||
| RUN pip install -r requirements.txt | ||
|
|
||
| COPY tests/selenium selenium | ||
| COPY tests/test_data test_data | ||
| COPY tests/simple_phrases_russian.wav simple_phrases_russian.wav | ||
|
|
||
| COPY app/config.py app/config.py | ||
| COPY app_conf/testing.ini app_conf/testing.ini | ||
|
|
||
| ENV PYTHONPATH='/usr/src/project/:/usr/src/project/app/' | ||
|
|
||
| # CMD ["pytest", "-s", "."] |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| version: '2' | ||
|
|
||
| services: | ||
| selenium-tests: | ||
| build: | ||
| context: . | ||
| dockerfile: Dockerfile_selenium | ||
| shm_size: 2g | ||
| depends_on: | ||
| - web | ||
| networks: | ||
| - default |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,2 @@ | ||
| pytest==8.0.2 | ||
| selenium==4.16.0 | ||
| webdriver-manager==4.0.1 | ||
| selenium==4.33.0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import pytest | ||
|
|
||
| from selenium_session import SeleniumSession, ROOT_DIR, chrome_options | ||
| from app.config import Config | ||
|
|
||
| CONFIG_PATH = f'{ROOT_DIR}/app_conf/testing.ini' | ||
| AUDIO_FILE = f"{ROOT_DIR}/simple_phrases_russian.wav" | ||
|
|
||
| @pytest.fixture(scope="module") | ||
| def selenium_session(): | ||
| Config.init_config(CONFIG_PATH) | ||
| session = SeleniumSession(Config.c, chrome_options(AUDIO_FILE)) | ||
|
|
||
| yield session | ||
|
|
||
| session.end_session() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| import requests | ||
| from time import sleep | ||
|
|
||
| from selenium.webdriver import Chrome | ||
|
|
||
| HOST = 'http://web:5000' | ||
| ROOT_DIR = '/usr/src/project' | ||
|
|
||
| from selenium.webdriver.chrome.options import Options | ||
|
|
||
| def chrome_options(audio_file=None): | ||
| chrome_options = Options() | ||
|
|
||
| chrome_options.add_argument('--no-sandbox') | ||
| chrome_options.add_argument('--headless') | ||
| chrome_options.add_argument(f'--unsafely-treat-insecure-origin-as-secure={HOST}') | ||
|
|
||
| if audio_file is not None: | ||
| chrome_options.add_argument("--disable-user-media-security") | ||
| chrome_options.add_argument("--use-fake-device-for-media-stream") | ||
| chrome_options.add_argument("--use-fake-ui-for-media-stream") | ||
| chrome_options.add_argument(f'--use-file-for-fake-audio-capture={audio_file}') | ||
|
|
||
| return chrome_options | ||
|
|
||
| class SeleniumSession: | ||
| def __init__(self, config, chrome_options, requires_init=True): | ||
| self.__prepare_session(HOST, config, chrome_options, requires_init) | ||
|
|
||
| def __init_driver(self, chrome_options): | ||
| self.driver = Chrome(options=chrome_options) | ||
| self.session = requests.Session() | ||
|
|
||
| sleep(5) | ||
|
|
||
| def __registrate(self, config): | ||
| self.session.request('POST',f'{self.host}/lti', data={ | ||
| 'lis_person_name_full': config.testing.lis_person_name_full, | ||
| 'ext_user_username': config.testing.session_id, | ||
| 'custom_task_id': config.testing.custom_task_id, | ||
| 'custom_task_description': config.testing.custom_task_description, | ||
| 'custom_attempt_count': config.testing.custom_attempt_count, | ||
| 'custom_required_points': config.testing.custom_required_points, | ||
| 'custom_criteria_pack_id': config.testing.custom_criteria_pack_id, | ||
| 'roles': config.testing.roles, | ||
| 'lis_outcome_service_url': config.testing.lis_outcome_service_url, | ||
| 'lis_result_sourcedid': config.testing.lis_result_source_did, | ||
| 'oauth_consumer_key': config.testing.oauth_consumer_key, | ||
| }) | ||
|
|
||
| def __prepare_session(self, host, config, chrome_options, requires_init): | ||
| self.host = host | ||
|
|
||
| self.__init_driver(chrome_options) | ||
|
|
||
| if requires_init: | ||
| self.driver.get(f'{self.host}/init/') | ||
|
|
||
| self.__registrate(config) | ||
|
|
||
| def end_session(self): | ||
| self.driver.quit() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| from time import sleep | ||
|
|
||
| from selenium_session import ROOT_DIR | ||
| from training_session import Training | ||
|
|
||
| PRESENTATION_FILE = f"{ROOT_DIR}/test_data/test_presentation_file_0.pdf" | ||
| ESTIMATED_PROCESSING_TIME_IN_SECONDS = 100 | ||
|
|
||
| class SimpleTraining: | ||
| def test_presentation_upload(self, selenium_session): | ||
| Training(selenium_session).upload_presentation(PRESENTATION_FILE) | ||
|
|
||
| def test_record_preparation(self, selenium_session): | ||
| Training(selenium_session).prepare_record() | ||
| sleep(5) | ||
|
|
||
| def test_button_next(self, selenium_session): | ||
| Training(selenium_session).next_slide() | ||
| sleep(5) | ||
|
|
||
| def test_training_session_end(self, selenium_session): | ||
| Training(selenium_session).end_training() | ||
| sleep(5) | ||
|
|
||
| def test_training_feedback(self, selenium_session): | ||
| got_feedback = Training(selenium_session).wait_for_feedback(ESTIMATED_PROCESSING_TIME_IN_SECONDS) | ||
| assert got_feedback, f"Проверка тренировки заняла более {ESTIMATED_PROCESSING_TIME_IN_SECONDS} секунд" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| from simple_training import SimpleTraining | ||
|
|
||
| class TestMain(SimpleTraining): | ||
| pass |
|
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| from time import sleep | ||
|
|
||
| from selenium_session import SeleniumSession | ||
|
|
||
| from selenium.webdriver.common.by import By | ||
| from selenium.webdriver.support import expected_conditions as EC | ||
| from selenium.webdriver.support.ui import WebDriverWait | ||
|
|
||
|
|
||
| class Training: | ||
| def __init__(self, selenium: SeleniumSession): | ||
| self.selenium = selenium | ||
|
|
||
| def upload_presentation(self, presentation_path): | ||
| self.selenium.driver.get(f'{self.selenium.host}/upload_presentation/') | ||
|
|
||
| file_input = WebDriverWait(self.selenium.driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input[type=file]"))) | ||
| file_input.send_keys(presentation_path) | ||
|
|
||
| WebDriverWait(self.selenium.driver, 5).until(EC.element_to_be_clickable((By.ID, "button-submit"))).click() | ||
|
|
||
| def prepare_record(self): | ||
| WebDriverWait(self.selenium.driver, 10).until(EC.element_to_be_clickable((By.ID, "record"))).click() | ||
|
|
||
| WebDriverWait(self.selenium.driver, 10).until(EC.presence_of_element_located((By.ID, "model-timer"))) | ||
|
|
||
| WebDriverWait(self.selenium.driver, 10).until(EC.invisibility_of_element((By.ID, "model-timer"))) | ||
|
|
||
| def next_slide(self): | ||
| WebDriverWait(self.selenium.driver, 10).until(EC.element_to_be_clickable((By.ID, "next"))).click() | ||
|
|
||
| def end_training(self): | ||
| WebDriverWait(self.selenium.driver, 5).until(EC.element_to_be_clickable((By.ID, "done"))).click() | ||
|
|
||
| WebDriverWait(self.selenium.driver, 5).until(lambda d : d.switch_to.alert).accept() | ||
|
|
||
| def wait_for_feedback(self, seconds): | ||
| feedback_flag = False | ||
| step_count = 10 | ||
| step = seconds / step_count | ||
|
|
||
| for _ in range(step_count): | ||
| self.selenium.driver.refresh() | ||
|
|
||
| feedback_elements = self.selenium.driver.find_elements(By.ID, 'feedback') | ||
|
|
||
| if feedback_elements and feedback_elements[0].text.startswith('Оценка за тренировку'): | ||
| feedback_flag = True | ||
| break | ||
|
|
||
| sleep(step) | ||
|
|
||
| return feedback_flag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Для информации (исправлять не нужно) - для разных образов (точнее Dockerfile'ов) можно указывать свои .dockerignore (ссылка)